summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2020-08-24 18:44:51 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2020-08-24 18:44:51 +0200
commitad38bc6ecb80ddeb562841b33258dd53659b1da6 (patch)
treee02e9c3ff760554fd87f70df0e18b88594091a48 /backend
parent9c23ed018d72eed2554f4f9cff1ae6e6bb0cd479 (diff)
New upstream version 1.0.31upstream/1.0.31
Diffstat (limited to 'backend')
-rw-r--r--backend/Makefile.am78
-rw-r--r--backend/avision.c1080
-rw-r--r--backend/avision.h64
-rw-r--r--backend/canon_dr.c8
-rw-r--r--backend/canon_lide70-common.c3023
-rw-r--r--backend/canon_lide70.c960
-rw-r--r--backend/canon_lide70.conf.in8
-rw-r--r--backend/dll.c4
-rw-r--r--backend/dll.conf.in1
-rw-r--r--backend/dmc.c100
-rw-r--r--backend/epsonds-net.c158
-rw-r--r--backend/epsonds-net.h4
-rw-r--r--backend/epsonds.c6
-rw-r--r--backend/escl.conf.in6
-rw-r--r--backend/escl/escl.c893
-rw-r--r--backend/escl/escl.h65
-rw-r--r--backend/escl/escl_capabilities.c194
-rw-r--r--backend/escl/escl_crop.c102
-rw-r--r--backend/escl/escl_jpeg.c69
-rw-r--r--backend/escl/escl_mupdf.c256
-rw-r--r--backend/escl/escl_newjob.c115
-rw-r--r--backend/escl/escl_pdf.c223
-rw-r--r--backend/escl/escl_png.c157
-rw-r--r--backend/escl/escl_reset.c42
-rw-r--r--backend/escl/escl_scan.c48
-rw-r--r--backend/escl/escl_status.c159
-rw-r--r--backend/escl/escl_tiff.c71
-rw-r--r--backend/fujitsu-scsi.h10
-rw-r--r--backend/fujitsu.c133
-rw-r--r--backend/fujitsu.conf.in9
-rw-r--r--backend/fujitsu.h10
-rw-r--r--backend/genesys.conf.in12
-rw-r--r--backend/genesys/buffer.cpp102
-rw-r--r--backend/genesys/buffer.h89
-rw-r--r--backend/genesys/calibration.h9
-rw-r--r--backend/genesys/command_set.h36
-rw-r--r--backend/genesys/command_set_common.cpp248
-rw-r--r--backend/genesys/command_set_common.h48
-rw-r--r--backend/genesys/conv.cpp238
-rw-r--r--backend/genesys/conv.h69
-rw-r--r--backend/genesys/device.cpp90
-rw-r--r--backend/genesys/device.h151
-rw-r--r--backend/genesys/enums.cpp242
-rw-r--r--backend/genesys/enums.h202
-rw-r--r--backend/genesys/error.cpp29
-rw-r--r--backend/genesys/error.h24
-rw-r--r--backend/genesys/fwd.h15
-rw-r--r--backend/genesys/genesys.cpp4079
-rw-r--r--backend/genesys/genesys.h20
-rw-r--r--backend/genesys/gl124.cpp1214
-rw-r--r--backend/genesys/gl124.h83
-rw-r--r--backend/genesys/gl646.cpp1986
-rw-r--r--backend/genesys/gl646.h403
-rw-r--r--backend/genesys/gl646_registers.h1
-rw-r--r--backend/genesys/gl841.cpp3123
-rw-r--r--backend/genesys/gl841.h21
-rw-r--r--backend/genesys/gl841_registers.h2
-rw-r--r--backend/genesys/gl842.cpp1066
-rw-r--r--backend/genesys/gl842.h128
-rw-r--r--backend/genesys/gl842_registers.h285
-rw-r--r--backend/genesys/gl843.cpp1955
-rw-r--r--backend/genesys/gl843.h21
-rw-r--r--backend/genesys/gl843_registers.h10
-rw-r--r--backend/genesys/gl846.cpp1763
-rw-r--r--backend/genesys/gl846.h96
-rw-r--r--backend/genesys/gl846_registers.h12
-rw-r--r--backend/genesys/gl847.cpp1883
-rw-r--r--backend/genesys/gl847.h84
-rw-r--r--backend/genesys/gl847_registers.h1
-rw-r--r--backend/genesys/image.cpp68
-rw-r--r--backend/genesys/image.h5
-rw-r--r--backend/genesys/image_buffer.cpp127
-rw-r--r--backend/genesys/image_buffer.h65
-rw-r--r--backend/genesys/image_pipeline.cpp211
-rw-r--r--backend/genesys/image_pipeline.h134
-rw-r--r--backend/genesys/image_pixel.h1
-rw-r--r--backend/genesys/low.cpp1234
-rw-r--r--backend/genesys/low.h275
-rw-r--r--backend/genesys/motor.cpp74
-rw-r--r--backend/genesys/motor.h76
-rw-r--r--backend/genesys/register.h8
-rw-r--r--backend/genesys/scanner_interface.h10
-rw-r--r--backend/genesys/scanner_interface_usb.cpp53
-rw-r--r--backend/genesys/scanner_interface_usb.h4
-rw-r--r--backend/genesys/sensor.cpp52
-rw-r--r--backend/genesys/sensor.h190
-rw-r--r--backend/genesys/settings.cpp73
-rw-r--r--backend/genesys/settings.h121
-rw-r--r--backend/genesys/tables_frontend.cpp148
-rw-r--r--backend/genesys/tables_gpo.cpp85
-rw-r--r--backend/genesys/tables_memory_layout.cpp164
-rw-r--r--backend/genesys/tables_model.cpp1391
-rw-r--r--backend/genesys/tables_motor.cpp496
-rw-r--r--backend/genesys/tables_motor_profile.cpp380
-rw-r--r--backend/genesys/tables_sensor.cpp4474
-rw-r--r--backend/genesys/test_scanner_interface.cpp12
-rw-r--r--backend/genesys/test_scanner_interface.h7
-rw-r--r--backend/genesys/test_settings.cpp10
-rw-r--r--backend/genesys/test_settings.h2
-rw-r--r--backend/genesys/test_usb_device.cpp25
-rw-r--r--backend/genesys/test_usb_device.h9
-rw-r--r--backend/genesys/usb_device.cpp24
-rw-r--r--backend/genesys/usb_device.h8
-rw-r--r--backend/genesys/utilities.h138
-rw-r--r--backend/genesys/value_filter.h140
-rw-r--r--backend/gt68xx.c7
-rw-r--r--backend/gt68xx.conf.in2
-rw-r--r--backend/gt68xx_high.c2
-rw-r--r--backend/gt68xx_mid.c12
-rw-r--r--backend/hp5400.h11
-rw-r--r--backend/hp5400_internal.c130
-rw-r--r--backend/hp5400_internal.h59
-rw-r--r--backend/hp5400_sane.c543
-rw-r--r--backend/kodakaio.c10
-rw-r--r--backend/kvs1025.c4
-rw-r--r--backend/kvs20xx_opt.c4
-rw-r--r--backend/kvs40xx_opt.c6
-rw-r--r--backend/mustek.c2
-rw-r--r--backend/net.c20
-rw-r--r--backend/pixma/.gitignore1
-rw-r--r--backend/pixma/pixma.c179
-rw-r--r--backend/pixma/pixma.h28
-rw-r--r--backend/pixma/pixma_bjnp.c201
-rw-r--r--backend/pixma/pixma_bjnp_private.h10
-rw-r--r--backend/pixma/pixma_common.c175
-rw-r--r--backend/pixma/pixma_common.h3
-rw-r--r--backend/pixma/pixma_imageclass.c10
-rw-r--r--backend/pixma/pixma_io_sanei.c2
-rw-r--r--backend/pixma/pixma_mp150.c192
-rw-r--r--backend/pixma/pixma_mp730.c4
-rw-r--r--backend/pixma/pixma_mp750.c4
-rw-r--r--backend/pixma/pixma_mp800.c135
-rw-r--r--backend/pixma/pixma_sane_options.c362
-rw-r--r--backend/pixma/pixma_sane_options.h51
-rwxr-xr-xbackend/pixma/scripts/pixma_gen_options.py102
-rw-r--r--backend/plustek-usbshading.c6
-rw-r--r--backend/ricoh2_buffer.c8
-rw-r--r--backend/test-picture.c4
-rw-r--r--backend/test.c113
-rw-r--r--backend/test.h4
-rw-r--r--backend/umax_pp_low.c2
-rw-r--r--backend/v4l.c3
-rw-r--r--backend/v4l.h139
-rw-r--r--backend/xerox_mfp.conf.in3
144 files changed, 21758 insertions, 18985 deletions
diff --git a/backend/Makefile.am b/backend/Makefile.am
index 4a947bf..2ac341c 100644
--- a/backend/Makefile.am
+++ b/backend/Makefile.am
@@ -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
@@ -501,10 +528,9 @@ libsane_fujitsu_la_LIBADD = $(COMMON_LIBS) libfujitsu.la ../sanei/sanei_init_deb
EXTRA_DIST += fujitsu.conf.in
libgenesys_la_SOURCES = genesys/genesys.cpp genesys/genesys.h \
- genesys/buffer.h genesys/buffer.cpp \
genesys/calibration.h \
genesys/command_set.h \
- genesys/conv.h genesys/conv.cpp \
+ genesys/command_set_common.h genesys/command_set_common.cpp \
genesys/device.h genesys/device.cpp \
genesys/enums.h genesys/enums.cpp \
genesys/error.h genesys/error.cpp \
@@ -512,6 +538,7 @@ libgenesys_la_SOURCES = genesys/genesys.cpp genesys/genesys.h \
genesys/gl646.cpp genesys/gl646.h genesys/gl646_registers.h \
genesys/gl124.cpp genesys/gl124.h genesys/gl124_registers.h \
genesys/gl841.cpp genesys/gl841.h genesys/gl841_registers.h \
+ genesys/gl842.cpp genesys/gl842.h genesys/gl842_registers.h \
genesys/gl843.cpp genesys/gl843.h genesys/gl843_registers.h \
genesys/gl846.cpp genesys/gl846.h genesys/gl846_registers.h \
genesys/gl847.cpp genesys/gl847.h genesys/gl847_registers.h \
@@ -532,15 +559,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
@@ -548,7 +576,10 @@ libgenesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys
nodist_libsane_genesys_la_SOURCES = genesys-s.cpp
libsane_genesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys
libsane_genesys_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
-libsane_genesys_la_LIBADD = $(COMMON_LIBS) libgenesys.la ../sanei/sanei_magic.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS)
+libsane_genesys_la_LIBADD = $(COMMON_LIBS) libgenesys.la \
+ ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \
+ ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo \
+ $(MATH_LIB) $(TIFF_LIBS) $(USB_LIBS) $(RESMGR_LIBS)
EXTRA_DIST += genesys.conf.in
libgphoto2_i_la_SOURCES = gphoto2.c gphoto2.h
@@ -682,10 +713,10 @@ libsane_kodak_la_LIBADD = $(COMMON_LIBS) libkodak.la ../sanei/sanei_init_debug.l
EXTRA_DIST += kodak.conf.in
libkodakaio_la_SOURCES = kodakaio.c kodakaio.h
-libkodakaio_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kodakaio
+libkodakaio_la_CPPFLAGS = $(AM_CPPFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=kodakaio
nodist_libsane_kodakaio_la_SOURCES = kodakaio-s.c
-libsane_kodakaio_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kodakaio
+libsane_kodakaio_la_CPPFLAGS = $(AM_CPPFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=kodakaio
libsane_kodakaio_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_kodakaio_la_LIBADD = $(COMMON_LIBS) libkodakaio.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo $(USB_LIBS) $(SOCKET_LIBS) $(AVAHI_LIBS) $(MATH_LIB) $(RESMGR_LIBS)
EXTRA_DIST += kodakaio.conf.in
@@ -904,15 +935,34 @@ 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
+
+# Generate options files included by pixma/pixma.c from said file.
+# The circular dependency means we cannot add it as a prerequisite
+# for the targets that build the options files.
+
+$(srcdir)/pixma/pixma.c: \
+ $(srcdir)/pixma/pixma_sane_options.h \
+ $(srcdir)/pixma/pixma_sane_options.c
+
+$(srcdir)/pixma/pixma_sane_options.h:
+ @echo Generating $@ from $(@D)/pixma.c
+ @(cd $(@D); python scripts/pixma_gen_options.py h < pixma.c > $(@F))
+$(srcdir)/pixma/pixma_sane_options.c:
+ @echo Generating $@ from $(@D)/pixma.c
+ @(cd $(@D); python scripts/pixma_gen_options.py < pixma.c > $(@F))
+
+EXTRA_DIST += pixma/pixma_sane_options.c
+EXTRA_DIST += pixma/pixma_sane_options.h
+EXTRA_DIST += pixma/scripts/pixma_gen_options.py
+CLEANFILES += pixma/pixma_sane_options.c
+CLEANFILES += pixma/pixma_sane_options.h
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
libplustek_la_SOURCES = plustek.c plustek.h
libplustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek
diff --git a/backend/avision.c b/backend/avision.c
index 55b5f4f..862a275 100644
--- a/backend/avision.c
+++ b/backend/avision.c
@@ -164,451 +164,583 @@ static Avision_HWEntry Avision_Device_List [] =
{ "AVISION", "AV100CS",
0, 0,
"Avision", "AV100CS",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "AVISION", "AV100IIICS",
0, 0,
"Avision", "AV100IIICS",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "AVISION", "AV100S",
0, 0,
"Avision", "AV100S",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x0638, 0x0A27,
"Avision", "AV120",
- AV_INT_STATUS},
+ AV_INT_STATUS,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A3C,
"Avision", "AV121",
- AV_INT_BUTTON | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA},
+ AV_INT_BUTTON | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="good" */
{ NULL, NULL,
0x0638, 0x0A33,
"Avision", "AV122",
- AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET},
+ AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA,
+ { 0, {0, 0}, {{0, 0}, {-12.7, 0}} }
+ },
/* comment="sheetfed duplex scanner" */
/* status="good" */
{ NULL, NULL,
0x0638, 0x0A93,
"Avision", "AV122 C2",
- AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_NOT_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET},
+ AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_NOT_KEEP_WINDOW | AV_DOES_KEEP_GAMMA,
+ { 0, {0, 0}, {{0, 0}, {-12.7, 0}} }
+ },
/* comment="sheetfed duplex scanner" */
/* status="good" */
{ NULL, NULL,
0x0638, 0x0A24,
"Avision", "AV210",
- AV_INT_BUTTON | AV_ACCEL_TABLE},
+ AV_INT_BUTTON | AV_ACCEL_TABLE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A25,
"Avision", "AV210",
- AV_INT_BUTTON | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN},
+ AV_INT_BUTTON | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A3A,
"Avision", "AV210C2",
- AV_INT_BUTTON | AV_GRAY_MODES},
+ AV_INT_BUTTON | AV_GRAY_MODES,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A2F,
"Avision", "AV210C2-G",
- AV_INT_BUTTON | AV_GRAY_MODES},
+ AV_INT_BUTTON | AV_GRAY_MODES,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x1A35,
"Avision", "AV210D2+",
- AV_INT_BUTTON | AV_USE_GRAY_FILTER},
+ AV_INT_BUTTON | AV_USE_GRAY_FILTER,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A23,
"Avision", "AV220",
- AV_INT_BUTTON | AV_GRAY_MODES},
+ AV_INT_BUTTON | AV_GRAY_MODES,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="duplex! sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A2A,
"Avision", "AV220C2",
- AV_INT_BUTTON | AV_CANCEL_BUTTON},
+ AV_INT_BUTTON | AV_CANCEL_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="duplex! sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A2B,
"Avision", "AV220D2",
- AV_INT_BUTTON | AV_CANCEL_BUTTON},
+ AV_INT_BUTTON | AV_CANCEL_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="duplex! sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x1A31,
"Avision", "AV220D2+",
- AV_INT_BUTTON | AV_CANCEL_BUTTON | AV_USE_GRAY_FILTER},
+ AV_INT_BUTTON | AV_CANCEL_BUTTON | AV_USE_GRAY_FILTER,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="duplex! sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A2C,
"Avision", "AV220+",
- AV_INT_BUTTON | AV_CANCEL_BUTTON},
+ AV_INT_BUTTON | AV_CANCEL_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="duplex! sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A2D,
"Avision", "AV220C2-G",
- AV_INT_BUTTON | AV_CANCEL_BUTTON},
+ AV_INT_BUTTON | AV_CANCEL_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="duplex! sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A2E,
"Avision", "AV220C2-B",
- AV_INT_BUTTON | AV_CANCEL_BUTTON},
+ AV_INT_BUTTON | AV_CANCEL_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="duplex! sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A94,
"Avision", "AV220-G",
- AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_FIRMWARE},
+ AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_FIRMWARE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="duplex! sheetfed scanner" */
/* status="complete" */
{ "AVISION", "AV240SC",
0, 0,
"Avision", "AV240SC",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "AVISION", "AV260CS",
0, 0,
"Avision", "AV260CS",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "AVISION", "AV360CS",
0, 0,
"Avision", "AV360CS",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "AVISION", "AV363CS",
0, 0,
"Avision", "AV363CS",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "AVISION", "AV420CS",
0, 0,
"Avision", "AV420CS",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "AVISION", "AV6120",
0, 0,
"Avision", "AV6120",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, "AV610",
0x0638, 0x0a18,
"Avision", "AV610",
- AV_GRAY_CALIB_BLUE | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN | AV_INT_BUTTON},
+ AV_GRAY_CALIB_BLUE | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN | AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x0638, 0x0a18,
"Avision", "AV600U Plus",
/* If this unit requires the AV_INT_STATUS flag, then we'll need to alter the code to deal with two different devices with the same USB id (AV610 above) */
- AV_GRAY_CALIB_BLUE | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN | /* AV_INT_STATUS | */ AV_INT_BUTTON},
+ AV_GRAY_CALIB_BLUE | AV_ACCEL_TABLE | AV_NO_64BYTE_ALIGN | /* AV_INT_STATUS | */ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x0638, 0x0a5e,
"Avision", "AV610C2",
- AV_NO_BACKGROUND | AV_INT_BUTTON}, /* cancel button -> sense abort! */
+ AV_NO_BACKGROUND | AV_INT_BUTTON, /* cancel button -> sense abort! */
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x0638, 0x0a41,
"Avision", "AM3000 Series",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="MFD" */
/* status="basic" */
{ NULL, NULL,
0x0638, 0x0a16,
"Avision", "DS610CU Scancopier",
- AV_INT_STATUS},
+ AV_INT_STATUS,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 600 dpi, A4" */
/* status="good" */
{ "AVISION", "AV620CS",
0, 0,
"Avision", "AV620CS",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 600 dpi" */
/* status="complete" */
{ "AVISION", "AV620CS Plus",
0, 0,
"Avision", "AV620CS Plus",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi" */
/* status="complete" */
{ "AVISION", "AV630CS",
0, 0,
"Avision", "AV630CS",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi" */
/* status="complete" */
{ "AVISION", "AV630CSL",
0, 0,
"Avision", "AV630CSL",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi" */
/* status="untested" */
{ "AVISION", "AV6240",
0, 0,
"Avision", "AV6240",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A13,
"Avision", "AV600U",
- AV_MULTI_CALIB_CMD | AV_ADF_BGR_ORDER_INVERT | AV_SOFT_SCALE | AV_INT_STATUS | AV_NO_BUTTON},
+ AV_MULTI_CALIB_CMD | AV_ADF_BGR_ORDER_INVERT | AV_SOFT_SCALE | AV_INT_STATUS | AV_NO_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 600 dpi" */
/* status="good" */
{ "AVISION", "AV660S",
0, 0,
"Avision", "AV660S",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="untested" */
{ "AVISION", "AV680S",
0, 0,
"Avision", "AV680S",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="untested" */
{ "AVISION", "AV690U",
0, 0,
"Avision", "AV690U",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 2400 dpi" */
/* status="untested" */
{ "AVISION", "AV800S",
0, 0,
"Avision", "AV800S",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="untested" */
{ "AVISION", "AV810C",
0, 0,
"Avision", "AV810C",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="untested" */
{ "AVISION", "AV820",
0, 0,
"Avision", "AV820",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="untested" */
{ "AVISION", "AV820C",
0, 0,
"Avision", "AV820C",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="complete" */
{ "AVISION", "AV820C Plus",
0, 0,
"Avision", "AV820C Plus",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="complete" */
{ "AVISION", "AV830C",
0, 0,
"Avision", "AV830C",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="complete" */
{ "AVISION", "AV830C Plus",
0, 0,
"Avision", "AV830C Plus",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="untested" */
{ "AVISION", "AV880",
0, 0,
"Avision", "AV880",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="untested" */
{ "AVISION", "AV880C",
0, 0,
"Avision", "AV880C",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="untested" */
{ "AVISION", "AV3200C",
0, 0,
"Avision", "AV3200C",
- AV_NON_INTERLACED_DUPLEX_300 | AV_FASTER_WITH_FILTER},
+ AV_NON_INTERLACED_DUPLEX_300 | AV_FASTER_WITH_FILTER,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="complete" */
{ "AVISION", "AV3200SU",
0x0638, 0x0A4E,
"Avision", "AV3200SU",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="complete" */
{ "AVISION", "AV3730SU",
0x0638, 0x0A4F,
"Avision", "AV3730SU",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="complete" */
{ "AVISION", "AV3750SU",
0x0638, 0x0A65,
"Avision", "AV3750SU",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="complete" */
{ "AVISION", "AV3800C",
0, 0,
"Avision", "AV3800C",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="complete" */
{ "AVISION", "AV3850SU",
0x0638, 0x0a66,
"Avision", "AV3850SU",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi" */
/* status="complete" */
{ "AVISION", "FB6000E",
0, 0,
"Avision", "FB6000E",
- AV_NON_INTERLACED_DUPLEX_300},
+ AV_NON_INTERLACED_DUPLEX_300,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi, A3 - duplex! - zero edge!" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0a82,
"Avision", "FB6080E",
- AV_NON_INTERLACED_DUPLEX_300},
+ AV_NON_INTERLACED_DUPLEX_300,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi, A3 - duplex! - zero edge!" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0a84,
"Avision", "FB2080E",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 600 dpi, zero-edge" ASIC 7 */
/* status="basic" */
{ "AVISION", "AV8000S",
0, 0,
"Avision", "AV8000S",
- AV_DOES_NOT_KEEP_WINDOW},
+ AV_DOES_NOT_KEEP_WINDOW,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi, A3" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0a4d,
"Avision", "AV8050U",
- AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA},
+ AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi, A3 - duplex!" */
/* status="complete" */
{ "AVISION", "AV8300",
0x0638, 0x0A40,
"Avision", "AV8300",
- AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA},
+ AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi, A3 - duplex!" */
/* status="complete" */
{ "AVISION", "AV8350",
0x0638, 0x0A68,
"Avision", "AV8350",
- AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA},
+ AV_NON_INTERLACED_DUPLEX_300 | AV_DOES_NOT_KEEP_GAMMA,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi, A3 - duplex!" */
/* status="complete" */
{ NULL, NULL,
0x0638, 0x0A61,
"Avision", "IT8300",
- AV_NON_INTERLACED_DUPLEX_300 | AV_ACCEL_TABLE},
+ AV_NON_INTERLACED_DUPLEX_300 | AV_ACCEL_TABLE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi, A3 - duplex!, LCD screen, paper sensors" */
/* status="good" */
{ NULL, NULL,
0x0638, 0x0AA1,
"Avision", "@V2500",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="" */
/* status="untested" */
{ NULL, NULL,
0x0638, 0x0A45,
"Avision", "@V5100",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi, A3 - duplex!, LCD screen, paper sensors" */
/* status="good" */
{ "AVISION", "AVA3",
0, 0,
"Avision", "AVA3",
- AV_FORCE_A3},
+ AV_FORCE_A3,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 600 dpi, A3" */
/* status="basic" */
@@ -617,21 +749,27 @@ static Avision_HWEntry Avision_Device_List [] =
{ "HP", "ScanJet 5300C",
0x03f0, 0x0701,
"Hewlett-Packard", "ScanJet 5300C",
- AV_INT_STATUS},
+ AV_INT_STATUS,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 2400 dpi - some FW revisions have x-axis image scaling problems over 1200 dpi" */
/* status="complete" */
{ "HP", "ScanJet 5370C",
0x03f0, 0x0701,
"Hewlett-Packard", "ScanJet 5370C",
- AV_MULTI_CALIB_CMD | AV_INT_STATUS},
+ AV_MULTI_CALIB_CMD | AV_INT_STATUS,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 2400 dpi - some FW revisions have x-axis image scaling problems over 1200 dpi" */
/* status="good" */
{ "hp", "scanjet 7400c",
0x03f0, 0x0801,
"Hewlett-Packard", "ScanJet 7400c",
- AV_LIGHT_CHECK_BOGUS | AV_NO_64BYTE_ALIGN | AV_INT_STATUS},
+ AV_LIGHT_CHECK_BOGUS | AV_NO_64BYTE_ALIGN | AV_INT_STATUS,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 2400 dpi - dual USB/SCSI interface" */
/* status="good" */
@@ -639,14 +777,18 @@ static Avision_HWEntry Avision_Device_List [] =
{ "hp", "scanjet 7450c",
0x03f0, 0x0801,
"Hewlett-Packard", "ScanJet 7450c",
- AV_NO_64BYTE_ALIGN | AV_INT_STATUS},
+ AV_NO_64BYTE_ALIGN | AV_INT_STATUS,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 2400 dpi - dual USB/SCSI interface" */
/* status="good" */
{ "hp", "scanjet 7490c",
0x03f0, 0x0801,
"Hewlett-Packard", "ScanJet 7490c",
- AV_NO_64BYTE_ALIGN | AV_INT_STATUS},
+ AV_NO_64BYTE_ALIGN | AV_INT_STATUS,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 1200 dpi - dual USB/SCSI interface" */
/* status="good" */
@@ -654,7 +796,9 @@ static Avision_HWEntry Avision_Device_List [] =
{ "HP", "C9930A",
0x03f0, 0x0b01,
"Hewlett-Packard", "ScanJet 8200",
- AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE},
+ AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 4800 (?) dpi - USB 2.0" */
/* status="good" */
@@ -662,7 +806,9 @@ static Avision_HWEntry Avision_Device_List [] =
{ "HP", "C9930A",
0x03f0, 0x0b01,
"Hewlett-Packard", "ScanJet 8250",
- AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE},
+ AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 4800 (?) dpi - USB 2.0" */
/* status="good" */
#endif
@@ -670,7 +816,9 @@ static Avision_HWEntry Avision_Device_List [] =
{ "HP", "C9930A",
0x03f0, 0x3905,
"Hewlett-Packard", "ScanJet 8270",
- AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE},
+ AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 4800 (?) dpi - USB 2.0" */
/* status="good" */
@@ -678,7 +826,9 @@ static Avision_HWEntry Avision_Device_List [] =
{ "HP", "C9930A",
0x03f0, 0x0b01,
"Hewlett-Packard", "ScanJet 8290",
- AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE},
+ AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 4800 (?) dpi - USB 2.0 and SCSI - only SCSI tested so far" */
/* status="good" */
@@ -686,7 +836,9 @@ static Avision_HWEntry Avision_Device_List [] =
{ "HP", "C9930A",
0x03f0, 0x3805,
"Hewlett-Packard", "ScanJet 8300",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 4800 (?) dpi - USB 2.0" */
/* status="good" */
@@ -694,14 +846,18 @@ static Avision_HWEntry Avision_Device_List [] =
{ "HP", "C9930A",
0x03f0, 0x3805,
"Hewlett-Packard", "ScanJet 8350",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 4800 (?) dpi - USB 2.0" */
/* status="good" */
{ "HP", "C9930A",
0x03f0, 0x3805,
"Hewlett-Packard", "ScanJet 8390",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 4800 (?) dpi - USB 2.0" */
/* status="good" */
@@ -709,79 +865,103 @@ static Avision_HWEntry Avision_Device_List [] =
{ "Minolta", "#2882",
0, 0,
"Minolta", "Dimage Scan Dual I",
- AV_FORCE_FILM | AV_NO_START_SCAN}, /* not AV_FILMSCANNER (no frame control) */
+ AV_FORCE_FILM | AV_NO_START_SCAN, /* not AV_FILMSCANNER (no frame control) */
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="basic" */
{ "Minolta", "#2887",
0, 0,
"Minolta", "Scan Multi Pro",
- AV_FORCE_FILM | AV_NO_START_SCAN}, /* AV_FILMSCANNER (frame control)? */
+ AV_FORCE_FILM | AV_NO_START_SCAN, /* not AV_FILMSCANNER (no frame control) */
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "MINOLTA", "FS-V1",
0x0638, 0x026a,
"Minolta", "Dimage Scan Dual II",
- AV_FILMSCANNER | AV_ONE_CALIB_CMD | AV_12_BIT_MODE},
+ AV_FILMSCANNER | AV_ONE_CALIB_CMD | AV_12_BIT_MODE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, film-scanner" */
/* status="good" */
{ "MINOLTA", "Elite II",
0x0686, 0x4004,
"Minolta", "Elite II",
- AV_FILMSCANNER | AV_ONE_CALIB_CMD},
+ AV_FILMSCANNER | AV_ONE_CALIB_CMD,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, film-scanner" */
/* status="untested" */
{ "MINOLTA", "FS-V3",
0x0686, 0x400d,
"Minolta", "Dimage Scan Dual III",
- AV_FILMSCANNER | AV_ONE_CALIB_CMD | AV_ACCEL_TABLE},
+ AV_FILMSCANNER | AV_ONE_CALIB_CMD | AV_ACCEL_TABLE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, film-scanner" */
/* status="good" */
{ "MINOLTA", "FS-V4",
0x0686, 0x400e,
"Minolta", "Dimage Scan Elite 5400",
- AV_FILMSCANNER | AV_ONE_CALIB_CMD | /*AV_ACCEL_TABLE |*/ AV_NO_START_SCAN},
+ AV_FILMSCANNER | AV_ONE_CALIB_CMD | /*AV_ACCEL_TABLE |*/ AV_NO_START_SCAN,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, film-scanner" */
/* status="good" */
{ "QMS", "SC-110",
0x0638, 0x0a15,
"Minolta-QMS", "SC-110",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="" */
/* status="untested" */
{ "QMS", "SC-215",
0x0638, 0x0a16,
"Minolta-QMS", "SC-215",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="" */
/* status="good" */
{ "MITSBISH", "MCA-ADFC",
0, 0,
"Mitsubishi", "MCA-ADFC",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "MITSBISH", "MCA-S1200C",
0, 0,
"Mitsubishi", "S1200C",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "MITSBISH", "MCA-S600C",
0, 0,
"Mitsubishi", "S600C",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "MITSBISH", "SS600",
0, 0,
"Mitsubishi", "SS600",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
/* The next are all untested ... */
@@ -789,209 +969,291 @@ static Avision_HWEntry Avision_Device_List [] =
{ "FCPA", "ScanPartner",
0, 0,
"Fujitsu", "ScanPartner",
- AV_FUJITSU},
+ AV_FUJITSU,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "FCPA", "ScanPartner 10",
0, 0,
"Fujitsu", "ScanPartner 10",
- AV_FUJITSU},
+ AV_FUJITSU,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "FCPA", "ScanPartner 10C",
0, 0,
"Fujitsu", "ScanPartner 10C",
- AV_FUJITSU},
+ AV_FUJITSU,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "FCPA", "ScanPartner 15C",
0, 0,
"Fujitsu", "ScanPartner 15C",
- AV_FUJITSU},
+ AV_FUJITSU,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "FCPA", "ScanPartner 300C",
0, 0,
"Fujitsu", "ScanPartner 300C",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "FCPA", "ScanPartner 600C",
0, 0,
"Fujitsu", "ScanPartner 600C",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "FCPA", "ScanPartner 620C",
0, 0,
"Fujitsu", "ScanPartner 620C",
- AV_LIGHT_CHECK_BOGUS},
+ AV_LIGHT_CHECK_BOGUS,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ "FCPA", "ScanPartner Jr",
0, 0,
"Fujitsu", "ScanPartner Jr",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ "FCPA", "ScanStation",
0, 0,
"Fujitsu", "ScanStation",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x04c5, 0x1029,
"Fujitsu", "fi-4010CU",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x04c5, 0x10ef,
"Fujitsu", "fi-5015C",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x040a, 0x6001,
"Kodak", "i30",
- AV_INT_BUTTON | AV_GRAY_MODES},
+ AV_INT_BUTTON | AV_GRAY_MODES,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x040a, 0x6002,
"Kodak", "i40",
- AV_INT_BUTTON | AV_GRAY_MODES},
+ AV_INT_BUTTON | AV_GRAY_MODES,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="basic" */
{ NULL, NULL,
0x040a, 0x6003,
"Kodak", "i50",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
#ifdef FAKE_ENTRIES_FOR_DESC_GENERATION
{ NULL, NULL,
0x040a, 0x6003,
"Kodak", "i55",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
#endif
{ NULL, NULL,
0x040a, 0x6004,
"Kodak", "i60",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
#ifdef FAKE_ENTRIES_FOR_DESC_GENERATION
{ NULL, NULL,
0x040a, 0x6004,
"Kodak", "i65",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
#endif
{ NULL, NULL,
0x040a, 0x6005,
"Kodak", "i80",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
+ { NULL, NULL,
+ 0x040a, 0x6013,
+ "Kodak", "i1120",
+ AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_USE_GRAY_FILTER | AV_SOFT_SCALE |
+ AV_FORCE_CALIB | AV_NO_QSCAN_MODE | AV_NO_QCALIB_MODE | AV_OVERSCAN_OPTDPI |
+ AV_NO_REAR | AV_FASTFEED_ON_CANCEL | AV_GAMMA_10 | AV_MULTI_SHEET_SCAN,
+ { /* offsets */
+ -1.5, /* first sheet (should be identical for single / duplex) */
+ {2.5, -6.0}, /* front-only scan */
+ {{2.0, -14.0}, {-10.0, -2.0}} /* duplex scan */
+ }
+ },
+ /* comment="duplex sheetfed scanner" */
+ /* status="good" */
+ /* This is a Kodak OEM device manufactured by avision.
+ It uses an Avision firmware modified by Kodak, so
+ some modifications needed to be done here. */
+
{ "iVina", "1200U",
0x0638, 0x0268,
"iVina", "1200U",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x04a7, 0x0424,
"Visioneer", "Strobe XP 450",
- AV_INT_BUTTON | AV_ACCEL_TABLE},
+ AV_INT_BUTTON | AV_ACCEL_TABLE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x0491,
"Visioneer", "Strobe XP 450-G",
- AV_INT_BUTTON | AV_ACCEL_TABLE},
+ AV_INT_BUTTON | AV_ACCEL_TABLE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x0479,
"Visioneer", "Strobe XP 470",
- AV_INT_BUTTON | AV_ACCEL_TABLE},
+ AV_INT_BUTTON | AV_ACCEL_TABLE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x048F,
"Visioneer", "Strobe XP 470-G",
- AV_INT_BUTTON | AV_ACCEL_TABLE},
+ AV_INT_BUTTON | AV_ACCEL_TABLE,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x0420,
"Visioneer", "9320",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x0421,
"Visioneer", "9450",
- AV_MULTI_CALIB_CMD | AV_ADF_BGR_ORDER_INVERT | AV_NO_BUTTON | AV_NO_TUNE_SCAN_LENGTH},
+ AV_MULTI_CALIB_CMD | AV_ADF_BGR_ORDER_INVERT | AV_NO_BUTTON | AV_NO_TUNE_SCAN_LENGTH,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x047A,
"Visioneer", "9450-G",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x0422,
"Visioneer", "9550",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x0390,
"Visioneer", "9650",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x047B,
"Visioneer", "9650-G",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x0423,
"Visioneer", "9750",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x0493,
"Visioneer", "9750-G",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x0497,
"Visioneer", "Patriot 430",
- AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET},
+ AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA,
+ { 0, {0, 0}, {{0, 0}, {-12.7, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
@@ -999,7 +1261,9 @@ static Avision_HWEntry Avision_Device_List [] =
{ NULL, NULL,
0x04a7, 0x048F,
"Visioneer", "Patriot 470",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
#endif
@@ -1007,150 +1271,198 @@ static Avision_HWEntry Avision_Device_List [] =
{ NULL, NULL,
0x04a7, 0x0498,
"Visioneer", "Patriot 680",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x0499,
"Visioneer", "Patriot 780",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="sheetfed scanner" */
/* status="complete" */
{ NULL, NULL,
0x04a7, 0x049C,
"Xerox", "DocuMate150",
- AV_INT_BUTTON | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_BACKGROUND_QUIRK},
+ AV_INT_BUTTON | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_BACKGROUND_QUIRK,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x04a7, 0x0477,
"Xerox", "DocuMate152",
- AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET | AV_BACKGROUND_QUIRK},
+ AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_BACKGROUND_QUIRK,
+ { 0, {0, 0}, {{0, 0}, {-12.7, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x04a7, 0x049D,
"Xerox", "DocuMate162",
- AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET | AV_BACKGROUND_QUIRK},
+ AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_BACKGROUND_QUIRK,
+ { 0, {0, 0}, {{0, 0}, {-12.7, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x04a7, 0x0448,
"Xerox", "DocuMate250",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x04a7, 0x0490,
"Xerox", "DocuMate250-G",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x04a7, 0x0449,
"Xerox", "DocuMate252",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x04a7, 0x048C,
"Xerox", "DocuMate252-G",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x04a7, 0x0476,
"Xerox", "DocuMate232",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x04a7, 0x044c,
"Xerox", "DocuMate262",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x04a7, 0x048D,
"Xerox", "DocuMate262-G",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x04a7, 0x04a7,
"Xerox", "DocuMate262i",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="good" */
{ NULL, NULL,
0x04a7, 0x0475,
"Xerox", "DocuMate272",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x04a7, 0x048E,
"Xerox", "DocuMate272-G",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x04a7, 0x0446,
"Xerox", "DocuMate510",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x04a7, 0x0495,
"Xerox", "DocuMate512",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x04a7, 0x047c,
"Xerox", "DocuMate510-G",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x04a7, 0x0447,
"Xerox", "DocuMate520",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x04a7, 0x0492,
"Xerox", "DocuMate520-G",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
#ifdef FAKE_ENTRIES_FOR_DESC_GENERATION
{ NULL, NULL,
0x04a7, 0x0498,
"Xerox", "DocuMate632",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
#endif
{ NULL, NULL,
0x04a7, 0x0478,
"Xerox", "DocuMate752",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
{ NULL, NULL,
0x04a7, 0x049A,
"Xerox", "DocuMate752",
- AV_INT_BUTTON},
+ AV_INT_BUTTON,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* status="untested" */
#ifdef FAKE_ENTRIES_FOR_DESC_GENERATION
{ NULL, NULL,
0x0638, 0x0a16,
"OKI", "S700 Scancopier",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, 600 dpi, A4" */
/* status="good" */
#endif
@@ -1158,14 +1470,18 @@ static Avision_HWEntry Avision_Device_List [] =
{ "B+H", "2000F",
0, 0,
"Bell+Howell", "2000F",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi, A4" */
/* status="basic" */
{ NULL, NULL,
0x0482, 0x0335,
"Kyocera", "FS-1016MFP",
- 0},
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ },
/* comment="1 pass, ??? dpi, A4" */
/* status="untested" */
@@ -1207,7 +1523,9 @@ Lexmark X4500 MFP
{ NULL, NULL,
0, 0,
NULL, NULL,
- 0}
+ 0,
+ { 0, {0, 0}, {{0, 0}, {0, 0}} }
+ }
};
#if 0
@@ -2584,16 +2902,156 @@ compute_parameters (Avision_Scanner* s)
s->avdimen.bry += overscan;
}
- /* rear offset compensation */
- if (s->avdimen.interlaced_duplex && dev->hw->feature_type & AV_REAR_OFFSET) {
- const double offset = 0.5; /* in current affected models 1/2 inch */
- s->avdimen.rear_offset = (int) (offset * s->avdimen.hw_yres);
- DBG (1, "sane_compute_parameters: rear_offset: %d!\n", s->avdimen.rear_offset);
- /* we do not limit against the bottom-y here, as rear offset always
- applies to ADF scans, only */
- }
- else {
- s->avdimen.rear_offset = 0;
+ /* ADF offset compensation
+ Calculate offsets for skipping lines later with considering overscan
+ which applies to both, front and rear. The difference needs to be cut
+ off on the other side. */
+ if (dev->adf_offset_compensation && s->avdimen.interlaced_duplex) {
+ /* ADF Duplex scan */
+
+ struct {
+ mm_offset front;
+ mm_offset rear;
+ } offsets = {{0, 0}, {0, 0}};
+
+ double overscan;
+ double bry_offset = 0;
+
+ /* top */
+ overscan = fmax(0, fmax(dev->hw->offset.duplex.front.top,
+ dev->hw->offset.duplex.rear.top));
+
+ offsets.front.top += overscan - dev->hw->offset.duplex.front.top;
+ offsets.rear.top += overscan - dev->hw->offset.duplex.rear.top;
+ bry_offset += overscan;
+
+ /* bottom */
+ overscan = fmax(0, fmax(dev->hw->offset.duplex.front.bottom,
+ dev->hw->offset.duplex.rear.bottom));
+
+ offsets.front.bottom += overscan - dev->hw->offset.duplex.front.bottom;
+ offsets.rear.bottom += overscan - dev->hw->offset.duplex.rear.bottom;
+ bry_offset += overscan;
+
+ /* first page offset */
+ if (dev->hw->feature_type & AV_MULTI_SHEET_SCAN) {
+ /* only applies to multi-sheet-scan */
+
+ if (dev->hw->offset.first > 0) {
+ /* move down:
+ - add top overscan in send_tune_scan_length (effective for all pages!)
+ - skip bottom lines at page n=0, front and rear
+ - skip top lines at page n>0, front and rear
+ */
+ if (s->page == 0) {
+ offsets.front.bottom += dev->hw->offset.first;
+ offsets.rear.bottom += dev->hw->offset.first;
+ } else {
+ offsets.front.top += dev->hw->offset.first;
+ offsets.rear.top += dev->hw->offset.first;
+ }
+
+ } else if (dev->hw->offset.first < 0) {
+ /* move up:
+ - add bottom overscan in send_tune_scan_length (effective for all pages!)
+ - skip top lines at page n=0, front and rear
+ - skip bottom lines at page n>0, front and rear
+ */
+ if (s->page == 0) {
+ offsets.front.top += fabs(dev->hw->offset.first);
+ offsets.rear.top += fabs(dev->hw->offset.first);
+ } else {
+ offsets.front.bottom += fabs(dev->hw->offset.first);
+ offsets.rear.bottom += fabs(dev->hw->offset.first);
+ }
+
+ }
+ bry_offset += fabs(dev->hw->offset.first);
+ }
+
+ /* convert to lines */
+ s->avdimen.offset.front.top = (int) ( offsets.front.top * s->avdimen.yres / MM_PER_INCH );
+ s->avdimen.offset.front.bottom = (int) ( offsets.front.bottom * s->avdimen.yres / MM_PER_INCH );
+ s->avdimen.offset.rear.top = (int) ( offsets.rear.top * s->avdimen.yres / MM_PER_INCH );
+ s->avdimen.offset.rear.bottom = (int) ( offsets.rear.bottom * s->avdimen.yres / MM_PER_INCH );
+
+ /* add overscan to bry (hw_lines) */
+ s->avdimen.bry += (long) ( bry_offset * s->avdimen.hw_yres / MM_PER_INCH );
+
+ DBG (1, "sane_compute_parameters: front offset: top: %d!\n",
+ s->avdimen.offset.front.top);
+ DBG (1, "sane_compute_parameters: front offset: bottom: %d!\n",
+ s->avdimen.offset.front.bottom);
+ DBG (1, "sane_compute_parameters: rear offset: top: %d!\n",
+ s->avdimen.offset.rear.top);
+ DBG (1, "sane_compute_parameters: rear offset: bottom: %d!\n",
+ s->avdimen.offset.rear.bottom);
+
+ } else if (dev->adf_offset_compensation && s->source_mode == AV_ADF) {
+ /* ADF front scan */
+
+ mm_offset offsets = {0, 0};
+ double bry_offset = 0;
+
+ /* top */
+ if (dev->hw->offset.front.top < 0)
+ offsets.top += fabs(dev->hw->offset.front.top);
+ else
+ bry_offset += dev->hw->offset.front.top;
+
+ /* bottom */
+ if (dev->hw->offset.front.bottom < 0)
+ offsets.bottom += fabs(dev->hw->offset.front.bottom);
+ else
+ bry_offset += dev->hw->offset.front.bottom;
+
+ /* first page offset */
+ if (dev->hw->feature_type & AV_MULTI_SHEET_SCAN) {
+ /* only applies to multi-sheet-scan */
+
+ if (dev->hw->offset.first > 0) {
+ /* move down:
+ - add top overscan in send_tune_scan_length (effective for all pages!)
+ - skip bottom lines at page n=0
+ - skip top lines at page n>0
+ */
+ if (s->page == 0)
+ offsets.bottom += dev->hw->offset.first;
+ else
+ offsets.top += dev->hw->offset.first;
+
+ } else if (dev->hw->offset.first < 0) {
+ /* move up:
+ - add bottom overscan in send_tune_scan_length (effective for all pages!)
+ - skip top lines at page n=0
+ - skip bottom lines at page n>0
+ */
+ if (s->page == 0)
+ offsets.top += fabs(dev->hw->offset.first);
+ else
+ offsets.bottom += fabs(dev->hw->offset.first);
+
+ }
+ bry_offset += fabs(dev->hw->offset.first);
+ }
+
+ /* convert to lines */
+ s->avdimen.offset.front.top = (int) ( offsets.top * s->avdimen.yres / MM_PER_INCH );
+ s->avdimen.offset.front.bottom = (int) ( offsets.bottom * s->avdimen.yres / MM_PER_INCH );
+
+ /* add overscan to bry (hw_lines) */
+ s->avdimen.bry += (long) ( bry_offset * s->avdimen.hw_yres / MM_PER_INCH );
+
+ DBG (1, "sane_compute_parameters: front offset: top: %d!\n",
+ s->avdimen.offset.front.top);
+ DBG (1, "sane_compute_parameters: front offset: bottom: %d!\n",
+ s->avdimen.offset.front.bottom);
+
+ } else {
+ s->avdimen.offset.front.top = 0;
+ s->avdimen.offset.front.bottom = 0;
+ s->avdimen.offset.rear.top = 0;
+ s->avdimen.offset.rear.bottom = 0;
}
memset (&s->params, 0, sizeof (s->params));
@@ -4088,6 +4546,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];
@@ -4365,7 +4825,10 @@ get_tune_scan_length (Avision_Scanner* s)
static SANE_Status
send_tune_scan_length (Avision_Scanner* s)
{
- int top, bottom;
+ Avision_Device* dev = s->hw;
+
+ int top, bottom, dpi;
+ double offset = 0;
SANE_Status status;
size_t size;
@@ -4385,10 +4848,34 @@ send_tune_scan_length (Avision_Scanner* s)
set_triple (scmd.transferlen, size);
/* the SPEC says optical DPI, but real world measuring suggests it is 1200
- as in the window descriptor */
- top = 1200 * SANE_UNFIX (s->val[OPT_OVERSCAN_TOP].w) / MM_PER_INCH;
+ as in the window descriptor.
+ MN: This is not true for at least Kodak i1120 where it is optical DPI
+ */
+ dpi = 1200;
+ if (dev->hw->feature_type & AV_OVERSCAN_OPTDPI)
+ dpi = dev->inquiry_optical_res;
+
+ top = dpi * SANE_UNFIX (s->val[OPT_OVERSCAN_TOP].w) / MM_PER_INCH;
DBG (3, "send_tune_scan_length: top: %d\n", top);
+ /* top offset compensation */
+ if (dev->adf_offset_compensation) {
+ if (s->avdimen.interlaced_duplex)
+ offset += fmax(0, fmax(dev->hw->offset.duplex.front.top,
+ dev->hw->offset.duplex.rear.top) );
+ else if (s->source_mode == AV_ADF)
+ offset += fmax(0, dev->hw->offset.front.top);
+
+ /* first page offset */
+ if (dev->hw->offset.first > 0)
+ offset += dev->hw->offset.first;
+
+ /* convert to lines */
+ int top_offset = dpi * offset / MM_PER_INCH;
+ top += top_offset;
+ DBG (3, "send_tune_scan_length: top offset: %d\n", top_offset);
+ }
+
set_double (scmd.datatypequal, 0x0001); /* attach, 0x000 is shorten */
set_double (payload.vertical, top);
/* set_double (payload.horizontal, 0); */
@@ -4405,9 +4892,28 @@ send_tune_scan_length (Avision_Scanner* s)
}
scmd.datatypecode = 0x95; /* Attach/Truncate tail(right) of scan length */
- bottom = 1200 * SANE_UNFIX (s->val[OPT_OVERSCAN_BOTTOM].w) / MM_PER_INCH;
+ bottom = dpi * SANE_UNFIX (s->val[OPT_OVERSCAN_BOTTOM].w) / MM_PER_INCH;
DBG (3, "send_tune_scan_length: bottom: %d\n", bottom);
+ /* bottom offset compensation */
+ offset = 0;
+ if (dev->adf_offset_compensation) {
+ if (s->avdimen.interlaced_duplex)
+ offset += fmax(0, fmax(dev->hw->offset.duplex.front.bottom,
+ dev->hw->offset.duplex.rear.bottom) );
+ else if (s->source_mode == AV_ADF)
+ offset += fmax(0, dev->hw->offset.front.bottom);
+
+ /* first page offset */
+ if (dev->hw->offset.first < 0)
+ offset += fabs(dev->hw->offset.first);
+
+ /* convert to lines */
+ int bottom_offset = dpi * offset / MM_PER_INCH;
+ bottom += bottom_offset;
+ DBG (3, "send_tune_scan_length: bottom offset: %d\n", bottom_offset);
+ }
+
set_double (payload.vertical, bottom);
/*set_double (payload.horizontal, 0); */
@@ -4973,7 +5479,7 @@ normal_calibration (Avision_Scanner* s)
return status;
/* check if need do calibration */
- if (calib_format.flags != 1) {
+ if (calib_format.flags != 1 && !(s->hw->hw->feature_type & AV_FORCE_CALIB)) {
DBG (1, "normal_calibration: Scanner claims no calibration needed -> skipped!\n");
return SANE_STATUS_GOOD;
}
@@ -4990,7 +5496,7 @@ normal_calibration (Avision_Scanner* s)
return SANE_STATUS_NO_MEM;
/* check if we need to do dark calibration (shading) */
- if (BIT(calib_format.ability1, 3))
+ if (BIT(calib_format.ability1, 2))
{
DBG (1, "normal_calibration: reading dark data\n");
/* read dark calib data */
@@ -5260,11 +5766,24 @@ send_gamma (Avision_Scanner* s)
v2 = 0;
}
- for (k = 0; k < gamma_values; ++ k, ++ i) {
- gamma_data [i] = (uint8_t)
- (((v1 * (gamma_values - k)) + (v2 * k) ) / (double) gamma_values);
- }
+ if (s->hw->hw->feature_type & AV_GAMMA_UINT16) {
+ /* Use some pointer-cast magic to use gamma_data as uint16 array
+ and write as big-endian since values get swapped */
+ ((uint16_t *)gamma_data) [i++] = (uint16_t)v1<<8;
+ } else {
+ /* interpolate gamma_values to gamma_data */
+ for (k = 0; k < gamma_values; ++ k, ++ i) {
+ gamma_data [i] = (uint8_t)
+ (((v1 * (gamma_values - k)) + (v2 * k) ) / (double) gamma_values);
+ }
+ }
+
}
+
+ /* with AV_GAMMA_UINT16 only every second value is filled, so double i */
+ if (s->hw->hw->feature_type & AV_GAMMA_UINT16)
+ i *= 2;
+
/* fill the gamma table - (e.g.) if 11bit (old protocol) table */
{
size_t t_i = i-1;
@@ -5597,8 +6116,10 @@ set_window (Avision_Scanner* s)
paralen += sizeof (cmd.window.avision.type.fujitsu);
else if (!dev->inquiry_new_protocol)
paralen += sizeof (cmd.window.avision.type.old);
- else
+ else if (dev->hw->feature_type & AV_MULTI_SHEET_SCAN)
paralen += sizeof (cmd.window.avision.type.normal);
+ else
+ paralen += sizeof (cmd.window.avision.type.normal) - 1;
DBG (2, "set_window: final paralen: %d\n", paralen);
@@ -5624,7 +6145,7 @@ set_window (Avision_Scanner* s)
set_quad (cmd.window.descriptor.width,
s->avdimen.hw_pixels_per_line * base_dpi_rel / s->avdimen.hw_xres + 1);
- line_count = s->avdimen.hw_lines + 2 * s->avdimen.line_difference + s->avdimen.rear_offset;
+ line_count = s->avdimen.hw_lines + 2 * s->avdimen.line_difference;
set_quad (cmd.window.descriptor.length,
line_count * base_dpi_rel / s->avdimen.hw_yres + 1);
@@ -5667,6 +6188,13 @@ set_window (Avision_Scanner* s)
DBG (3, "set_window: filling ADF bits\n");
SET_BIT (cmd.window.avision.bitset1, 7);
+ if (dev->hw->feature_type & AV_MULTI_SHEET_SCAN) {
+ /* Always set bit 7 to enable single_sheet_scan option (defaults to off).
+ This removes the 1s pause between two sheets and fixes some offsets. */
+ SET_BIT(cmd.window.avision.type.normal.bitset3, 7);
+ cmd.window.avision.type.normal.single_sheet_scan = 0;
+ }
+
/* normal, interlaced duplex scanners */
if (dev->inquiry_duplex_interlaced) {
DBG (3, "set_window: interlaced duplex type\n");
@@ -5694,12 +6222,14 @@ set_window (Avision_Scanner* s)
if ( !(dev->hw->feature_type & AV_FUJITSU) )
{
/* quality scan option switch */
- if (s->val[OPT_QSCAN].w == SANE_TRUE) {
+ if (s->val[OPT_QSCAN].w == SANE_TRUE &&
+ !(dev->hw->feature_type & AV_NO_QSCAN_MODE)) {
SET_BIT (cmd.window.avision.type.normal.bitset2, 4);
}
/* quality calibration option switch (inverted! if set == speed) */
- if (s->val[OPT_QCALIB].w == SANE_FALSE) {
+ if (s->val[OPT_QCALIB].w == SANE_FALSE &&
+ !(dev->hw->feature_type & AV_NO_QCALIB_MODE)) {
SET_BIT (cmd.window.avision.type.normal.bitset2, 3);
}
@@ -6172,7 +6702,8 @@ start_scan (Avision_Scanner* s)
SET_BIT(cmd.bitset1,6);
}
- if (s->val[OPT_QSCAN].w == SANE_TRUE) {
+ if (s->val[OPT_QSCAN].w == SANE_TRUE &&
+ !(s->hw->hw->feature_type & AV_NO_QSCAN_MODE)) {
SET_BIT(cmd.bitset1,7);
}
@@ -6216,12 +6747,19 @@ do_eof (Avision_Scanner *s)
static SANE_Status
do_cancel (Avision_Scanner* s)
{
+ int status;
+
DBG (3, "do_cancel:\n");
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;
@@ -6232,6 +6770,12 @@ do_cancel (Avision_Scanner* s)
sanei_thread_invalidate (s->reader_pid);
}
+ if (s->hw->hw->feature_type & AV_FASTFEED_ON_CANCEL) {
+ status = release_unit (s, 1);
+ if (status != SANE_STATUS_GOOD)
+ DBG (1, "do_cancel: release_unit failed\n");
+ }
+
return SANE_STATUS_CANCELLED;
}
@@ -6496,6 +7040,8 @@ init_options (Avision_Scanner* s)
s->opt[OPT_QSCAN].type = SANE_TYPE_BOOL;
s->opt[OPT_QSCAN].unit = SANE_UNIT_NONE;
s->val[OPT_QSCAN].w = SANE_TRUE;
+ if (dev->hw->feature_type & AV_NO_QSCAN_MODE)
+ s->opt[OPT_QSCAN].cap |= SANE_CAP_INACTIVE;
/* Quality Calibration */
s->opt[OPT_QCALIB].name = SANE_NAME_QUALITY_CAL;
@@ -6504,6 +7050,8 @@ init_options (Avision_Scanner* s)
s->opt[OPT_QCALIB].type = SANE_TYPE_BOOL;
s->opt[OPT_QCALIB].unit = SANE_UNIT_NONE;
s->val[OPT_QCALIB].w = SANE_TRUE;
+ if (dev->hw->feature_type & AV_NO_QCALIB_MODE)
+ s->opt[OPT_QCALIB].cap |= SANE_CAP_INACTIVE;
/* gray scale gamma vector */
s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR;
@@ -6716,8 +7264,10 @@ reader_process (void *data)
sigset_t sigterm_set;
sigset_t ignore_set;
struct SIGACTION act;
+ int old;
FILE* fp;
+ FILE* fp_fd = 0; /* for ADF bottom offset truncating */
FILE* rear_fp = 0; /* used to store the deinterlaced rear data */
FILE* raw_fp = 0; /* used to write the RAW image data for debugging */
@@ -6757,21 +7307,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);
@@ -6792,6 +7351,16 @@ reader_process (void *data)
if (!fp)
return SANE_STATUS_NO_MEM;
+ if (dev->adf_offset_compensation) {
+ DBG (3, "reader_process: redirecting output data to temp file for ADF offset compensation.\n");
+ fp_fd = fp;
+ fp = fopen (s->duplex_offtmp_fname, "w+");
+ if (!fp) {
+ fclose(fp_fd);
+ return SANE_STATUS_NO_MEM;
+ }
+ }
+
/* start scan ? */
if ((deinterlace == NONE && !((dev->hw->feature_type & AV_ADF_FLIPPING_DUPLEX) && s->source_mode == AV_ADF_DUPLEX && s->duplex_rear_valid)) ||
(deinterlace != NONE && !s->duplex_rear_valid))
@@ -6897,9 +7466,9 @@ reader_process (void *data)
}
/* calculate params for the reading loop */
- total_size = s->avdimen.hw_bytes_per_line * (s->avdimen.hw_lines +
- 2 * s->avdimen.line_difference +
- s->avdimen.rear_offset);
+ total_size = s->avdimen.hw_bytes_per_line *
+ (s->avdimen.hw_lines + 2 * s->avdimen.line_difference);
+
if (deinterlace != NONE && !s->duplex_rear_valid)
total_size *= 2;
DBG (3, "reader_process: total_size: %lu\n", (u_long) total_size);
@@ -6958,9 +7527,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 */
@@ -7255,24 +7837,7 @@ reader_process (void *data)
if (s->avdimen.hw_xres == s->avdimen.xres &&
s->avdimen.hw_yres == s->avdimen.yres) /* No scaling */
{
- int lines, _hw_line = hw_line;
- uint8_t* src = out_data;
- /* we support cropping at the beginning and end due to rear offset */
- for (lines = useful_bytes / s->avdimen.hw_bytes_per_line;
- lines > 0; --lines, ++_hw_line, src += s->avdimen.hw_bytes_per_line)
- {
- if (deinterlace != NONE) {
- /* crop rear offset :-( */
- if ( (!s->duplex_rear_valid && _hw_line >= s->avdimen.hw_lines) ||
- (s->duplex_rear_valid && _hw_line < s->avdimen.rear_offset) )
- {
- DBG (7, "reader_process: skip due read offset line: %d\n", line);
- continue;
- }
- }
- fwrite (src, s->avdimen.hw_bytes_per_line, 1, fp);
- ++line;
- }
+ fwrite (out_data, useful_bytes, 1, fp);
}
else /* Software scaling - watch out - this code bites back! */
{
@@ -7296,22 +7861,11 @@ reader_process (void *data)
unsigned int v; /* accumulator */
/* Break out if we do not have the hw source line - yet,
- or when we are past the end of wanted data (e.g. on the
- front page due to rear_offset). Also take the read_offset
- into account on the rear side */
- if (deinterlace != NONE) {
- if (!s->duplex_rear_valid && syy >= s->avdimen.hw_lines) {
- DBG (7, "reader_process: skip due past intended front page lines: %d\n", sy);
- break;
- }
- else if (s->duplex_rear_valid) {
- /* the beginning is to be skipped, accessed thru offset */
- DBG (7, "reader_process: rear_offset adjusting source: %d\n", sy);
- sy += s->avdimen.rear_offset;
- syy += s->avdimen.rear_offset;
- }
+ or when we are past the end of wanted data */
+ if (deinterlace != NONE && !s->duplex_rear_valid && syy >= s->avdimen.hw_lines) {
+ DBG (7, "reader_process: skip due past intended front page lines: %d\n", sy);
+ break;
}
-
if (sy >= hw_line_end || syy >= hw_line_end) {
DBG (3, "reader_process: source line %d-%d not yet avail\n",
sy, syy);
@@ -7466,6 +8020,35 @@ reader_process (void *data)
}
}
+ /* ADF offset compensation */
+ if (dev->adf_offset_compensation) {
+
+ long lines;
+ uint8_t* buffer;
+
+ buffer = malloc (s->params.bytes_per_line);
+ lines = ftell(fp) / s->params.bytes_per_line;
+ rewind(fp);
+
+ for (long line = 0; line < lines; line++) {
+ fread(buffer, s->params.bytes_per_line, 1, fp);
+
+ if ( (!s->duplex_rear_valid && (line < s->avdimen.offset.front.top)) ||
+ (s->duplex_rear_valid && (line < s->avdimen.offset.rear.top)) ) {
+ DBG (7, "reader_process: skip due read offset line: %ld\n", line);
+ continue;
+ }
+
+ if ( (!s->duplex_rear_valid && (line > (lines - s->avdimen.offset.front.bottom))) ||
+ (s->duplex_rear_valid && (line > (lines - s->avdimen.offset.rear.bottom))) ) {
+ DBG (7, "reader_process: skip due read offset line: %ld to %ld\n", line, lines);
+ break; /* nothing more to write, so break out here */
+ }
+
+ fwrite(buffer, s->params.bytes_per_line, 1, fp_fd);
+ }
+ }
+
/* Eject film holder and/or release_unit - but only for
non-duplex-rear / non-virtual scans. */
if ((deinterlace != NONE && s->duplex_rear_valid) ||
@@ -7527,6 +8110,9 @@ reader_process (void *data)
if (rear_fp)
fclose (rear_fp);
+ if (fp_fd)
+ fclose(fp_fd);
+
if (ip_data) free (ip_data);
if (ip_history)
free (ip_history);
@@ -7859,9 +8445,17 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle)
http://www.poynton.com/GammaFAQ.html
- Avision's driver defaults to 2.2 though. */
+ Avision's driver defaults to 2.2 though.
+
+ MN: This is not true for at least Kodak i1120's windows driver.
+ Some real-world testing showed that a gamma of 1.0 is needed
+ for this scanner to give decent scan results. Add an option for this...
+ */
+
{
- const double gamma = 2.22;
+ double gamma = 2.22;
+ if (s->hw->hw->feature_type & AV_GAMMA_10)
+ gamma = 1.0;
const double one_over_gamma = 1. / gamma;
for (i = 0; i < 4; ++ i)
@@ -7915,6 +8509,29 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle)
/* initialize the options */
init_options (s);
+ if (dev->inquiry_duplex_interlaced &&
+ (dev->hw->offset.first != 0 ||
+ dev->hw->offset.front.top != 0 ||
+ dev->hw->offset.front.bottom != 0 ||
+ dev->hw->offset.duplex.front.top != 0 ||
+ dev->hw->offset.duplex.front.bottom != 0 ||
+ dev->hw->offset.duplex.rear.top != 0 ||
+ dev->hw->offset.duplex.rear.bottom != 0) )
+ dev->adf_offset_compensation = SANE_TRUE;
+
+ if (dev->adf_offset_compensation) {
+ strncpy(s->duplex_offtmp_fname, "/tmp/avision-offtmp-XXXXXX", PATH_MAX);
+
+ if (! mktemp(s->duplex_offtmp_fname) ) {
+ DBG (1, "sane_open: failed to generate temporary fname for ADF offset compensation temp file\n");
+ return SANE_STATUS_NO_MEM;
+ }
+ else {
+ DBG (1, "sane_open: temporary fname for ADF offset compensation temp file: %s\n",
+ s->duplex_offtmp_fname);
+ }
+ }
+
if (dev->inquiry_duplex_interlaced || dev->scanner_type == AV_FILM ||
dev->hw->feature_type & AV_ADF_FLIPPING_DUPLEX) {
/* Might need at least *DOS (Windows flavour and OS/2) portability fix
@@ -8026,6 +8643,11 @@ sane_close (SANE_Handle handle)
*(s->duplex_rear_fname) = 0;
}
+ if (*(s->duplex_offtmp_fname)) {
+ unlink (s->duplex_offtmp_fname);
+ *(s->duplex_offtmp_fname) = 0;
+ }
+
free (handle);
}
@@ -8332,7 +8954,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 +9182,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;
diff --git a/backend/avision.h b/backend/avision.h
index 58552c0..9017bf2 100644
--- a/backend/avision.h
+++ b/backend/avision.h
@@ -81,6 +81,12 @@ typedef struct Avision_Connection {
} Avision_Connection;
+/* structure for ADF offsets in mm */
+typedef struct mm_offset {
+ double top;
+ double bottom;
+} mm_offset;
+
typedef struct Avision_HWEntry {
const char* scsi_mfg;
const char* scsi_model;
@@ -184,9 +190,6 @@ typedef struct Avision_HWEntry {
/* does the scanner contain a Cancel button? */
#define AV_CANCEL_BUTTON ((uint64_t)1<<28)
- /* is the rear image offset? */
- #define AV_REAR_OFFSET ((uint64_t)1<<29)
-
/* some devices do not need a START_SCAN, even hang with it */
#define AV_NO_START_SCAN ((uint64_t)1<<30)
@@ -204,9 +207,46 @@ typedef struct Avision_HWEntry {
/* For scanners which need to have their firmware read to properly function. */
#define AV_FIRMWARE ((uint64_t)1<<35)
+ /* at least Kodak i1120 claims no calibration needed but windows driver does it anyways */
+ #define AV_FORCE_CALIB ((uint64_t)1<<36)
+
+ /* at least Kodak i1120 does not have an explicit "quality-scan" mode */
+ #define AV_NO_QSCAN_MODE ((uint64_t)1<<37)
+
+ /* at least Kodak i1120 optical DPI is used for overscan calculation */
+ #define AV_OVERSCAN_OPTDPI ((uint64_t)1<<38)
+
+ /* some scanners support fast feed-out of the sheet when cancelling a running scan */
+ #define AV_FASTFEED_ON_CANCEL ((uint64_t)1<<39)
+
+ /* at least Kodak i1120 does not have an explicit "quality-calibration" mode */
+ #define AV_NO_QCALIB_MODE ((uint64_t)1<<40)
+
+ /* Kodak i1120 needs gamma = 1.0 to give decent results */
+ #define AV_GAMMA_10 ((uint64_t)1<<41)
+
+ /* Kodak i1120 has a different gamma table format (like a uint16/double array) */
+ #define AV_GAMMA_UINT16 ((uint64_t)1<<42)
+
+ /* Kodak i1120 has single-sheet and multi-sheet scan modes. This option sets
+ bitset3[7] which enables multi-sheet scan by default so there is no pause
+ of 1s between two sheets in ADF scan mode. This also fixes some offsets
+ when scanning multiple sheets. */
+ #define AV_MULTI_SHEET_SCAN ((uint64_t)1<<43)
+
/* maybe more ...*/
uint64_t feature_type;
+ /* ADF offsets in mm */
+ struct {
+ float first; /* offset difference first sheet */
+ mm_offset front; /* front-only */
+ struct {
+ mm_offset front;
+ mm_offset rear;
+ } duplex;
+ } offset;
+
} Avision_HWEntry;
typedef enum {
@@ -301,6 +341,13 @@ enum Avision_Option
NUM_OPTIONS /* must come last */
};
+/* structure for ADF offsets in pixels of HW res */
+typedef struct hwpx_offset {
+ int top;
+ int bottom;
+} hwpx_offset;
+
+
typedef struct Avision_Dimensions
{
/* in dpi */
@@ -315,7 +362,11 @@ typedef struct Avision_Dimensions
/* in pixels */
int line_difference;
- int rear_offset; /* in pixels of HW res */
+
+ struct {
+ hwpx_offset front;
+ hwpx_offset rear;
+ } offset;
/* interlaced duplex scan */
SANE_Bool interlaced_duplex;
@@ -407,6 +458,8 @@ typedef struct Avision_Device
int inquiry_bits_per_channel;
int inquiry_no_gray_modes;
+ SANE_Bool adf_offset_compensation;
+
int scsi_buffer_size; /* nice to have SCSI buffer size */
int read_stripe_size; /* stripes to be read at-a-time */
@@ -451,6 +504,7 @@ typedef struct Avision_Scanner
/* Internal data for duplex scans */
char duplex_rear_fname [PATH_MAX];
+ char duplex_offtmp_fname [PATH_MAX];
SANE_Bool duplex_rear_valid;
color_mode c_mode;
@@ -670,6 +724,8 @@ typedef struct command_set_window_window
uint8_t line_width_msb;
uint8_t line_count_msb;
uint8_t background_lines;
+
+ uint8_t single_sheet_scan; /* from Kodak SVT tool */
} normal;
struct {
diff --git a/backend/canon_dr.c b/backend/canon_dr.c
index f6cd5d4..17ee7b6 100644
--- a/backend/canon_dr.c
+++ b/backend/canon_dr.c
@@ -3951,10 +3951,12 @@ get_pixelsize(struct scanner *s)
in, &inLen
);
- if(ret == SANE_STATUS_GOOD &&
- get_R_PSIZE_width(in) > 0 &&
- get_R_PSIZE_length(in) > 0){
+ if(ret != SANE_STATUS_GOOD){
+ DBG (10, "get_pixelsize: error reading, status = %d\n", ret);
+ break;
+ }
+ if(get_R_PSIZE_width(in) > 0 && get_R_PSIZE_length(in) > 0){
DBG (15, "get_pixelsize: w:%d h:%d\n",
get_R_PSIZE_width(in) * s->u.dpi_x / 1200,
get_R_PSIZE_length(in) * s->u.dpi_y / 1200);
diff --git a/backend/canon_lide70-common.c b/backend/canon_lide70-common.c
new file mode 100644
index 0000000..a0eb5c0
--- /dev/null
+++ b/backend/canon_lide70-common.c
@@ -0,0 +1,3023 @@
+/* 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 */
+
+#include <errno.h>
+#include <fcntl.h> /* open */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h> /* usleep */
+#include <time.h>
+#include <math.h> /* exp() */
+#ifdef HAVE_OS2_H
+#include <sys/types.h> /* mode_t */
+#endif
+#include <sys/stat.h>
+
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_RECIP_DEVICE 0x00
+#define USB_DIR_OUT 0x00
+#define USB_DIR_IN 0x80
+
+#define MSEC 1000 /* 1ms = 1000us */
+
+/* Assign status and verify a good return code */
+#define CHK(A) {if ((status = A) != SANE_STATUS_GOOD) {\
+ DBG (1, "Failure on line of %s: %d\n", \
+ __FILE__, __LINE__ ); return A; }}
+
+typedef SANE_Byte byte;
+
+/*****************************************************
+ Canon LiDE70 calibration and scan
+******************************************************/
+
+/* at 600 dpi */
+#define CANON_MAX_WIDTH 5104 /* 8.5in */
+/* this may not be right */
+#define CANON_MAX_HEIGHT 7300 /* 11.66in */
+/* Just for my scanner, or is this universal? Calibrate? */
+
+/* data structures and constants */
+typedef struct CANON_Handle
+{
+ /* options */
+ SANE_Option_Descriptor opt[num_options];
+ Option_Value val[num_options];
+ SANE_Parameters params;
+
+ SANE_Word graymode;
+ char *product; /* product name */
+ int fd; /* scanner fd */
+ int x1, x2, y1, y2; /* in pixels, at 600 dpi */
+ long width, height; /* at scan resolution */
+ unsigned char value_08, value_09; /* left */
+ unsigned char value_0a, value_0b; /* right */
+ unsigned char value_67, value_68; /* bottom */
+ unsigned char value_51; /* lamp colors */
+ int resolution; /* dpi */
+ char *fname; /* output file name */
+ FILE *fp; /* output file pointer (for reading) */
+ unsigned char absolute_threshold;
+}
+CANON_Handle;
+
+
+static byte cmd_buffer[] = { 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, 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, 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, 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,
+ 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, 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, 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, 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,
+ 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, 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, 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, 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,
+ 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, 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, 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, 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,
+ 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*****************************************************
+ CP2155 communication primitives
+ Provides I/O routines to Philips CP2155BE chip
+******************************************************/
+
+typedef int CP2155_Register;
+
+/* Write single byte to CP2155 register */
+static SANE_Status
+cp2155_set (int fd, CP2155_Register reg, byte data)
+{
+ SANE_Status status;
+ size_t count;
+
+ cmd_buffer[0] = (reg >> 8) & 0xff;
+ cmd_buffer[1] = (reg) & 0xff;
+ cmd_buffer[2] = 0x01;
+ cmd_buffer[3] = 0x00;
+ cmd_buffer[4] = data;
+
+ count = 5;
+ status = sanei_usb_write_bulk (fd, cmd_buffer, &count);
+
+ if (status != SANE_STATUS_GOOD)
+ {
+ DBG (1, "cp2155_set: sanei_usb_write_bulk error\n");
+ }
+
+ return status;
+}
+
+/* Read single byte from CP2155 register */
+static SANE_Status
+cp2155_get (int fd, CP2155_Register reg, byte * data)
+{
+ SANE_Status status;
+ size_t count;
+
+ cmd_buffer[0] = 0x01;
+ cmd_buffer[1] = (reg) & 0xff;
+ cmd_buffer[2] = 0x01;
+ cmd_buffer[3] = 0x00;
+
+ count = 4;
+ status = sanei_usb_write_bulk (fd, cmd_buffer, &count);
+
+ if (status != SANE_STATUS_GOOD)
+ {
+ DBG (1, "cp2155_get: sanei_usb_write_bulk error\n");
+ return status;
+ }
+
+ usleep (1 * MSEC);
+
+ count = 1;
+ status = sanei_usb_read_bulk (fd, data, &count);
+
+ if (status != SANE_STATUS_GOOD)
+ {
+ DBG (1, "cp2155_get: sanei_usb_read_bulk error\n");
+ }
+
+ return status;
+}
+
+/* Write a block of data to CP2155 chip */
+static SANE_Status
+cp2155_write (int fd, byte * data, size_t size)
+{
+ SANE_Status status;
+ size_t count = size + 4;
+
+ cmd_buffer[0] = 0x04;
+ cmd_buffer[1] = 0x70;
+ cmd_buffer[2] = (size) & 0xff;
+ cmd_buffer[3] = (size >> 8) & 0xff;
+ memcpy (cmd_buffer + 4, data, size);
+
+ status = sanei_usb_write_bulk (fd, cmd_buffer, &count);
+
+ if (status != SANE_STATUS_GOOD)
+ {
+ DBG (1, "cp2155_write: sanei_usb_write_bulk error\n");
+ }
+
+ return status;
+}
+
+/* Read a block of data from CP2155 chip */
+static SANE_Status
+cp2155_read (int fd, byte * data, size_t size)
+{
+ SANE_Status status;
+ size_t count;
+
+ cmd_buffer[0] = 0x05;
+ cmd_buffer[1] = 0x70;
+ cmd_buffer[2] = (size) & 0xff;
+ cmd_buffer[3] = (size >> 8) & 0xff;
+
+ count = 4;
+ status = sanei_usb_write_bulk (fd, cmd_buffer, &count);
+
+ if (status != SANE_STATUS_GOOD)
+ {
+ DBG (1, "cp2155_read: sanei_usb_write_bulk error\n");
+ return status;
+ }
+
+ usleep (1 * MSEC);
+
+ count = size;
+ status = sanei_usb_read_bulk (fd, data, &count);
+/*
+ if (status != SANE_STATUS_GOOD)
+ {
+ DBG (1, "cp2155_read: sanei_usb_read_bulk error %lu\n", (u_long) count);
+ }
+*/
+ return status;
+}
+
+/*****************************************************/
+
+static void
+cp2155_block1 (int fd, byte v001, unsigned int addr, byte * data, size_t size)
+{
+ size_t count = size;
+
+ while ((count & 0x0f) != 0)
+ {
+ count++;
+ }
+
+ byte pgLO = (count) & 0xff;
+ byte pgHI = (count >> 8) & 0xff;
+/*
+ DBG (1, "cp2155_block1 %06x %02x %04lx %04lx\n", addr, v001, (u_long) size,
+ (u_long) count);
+*/
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, v001);
+ cp2155_set (fd, 0x72, pgHI);
+ cp2155_set (fd, 0x73, pgLO);
+ cp2155_set (fd, 0x74, (addr >> 16) & 0xff);
+ cp2155_set (fd, 0x75, (addr >> 8) & 0xff);
+ cp2155_set (fd, 0x76, (addr) & 0xff);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ cp2155_write (fd, data, count);
+}
+
+/* size=0x0100 */
+/* gamma table red*/
+static byte cp2155_gamma_red_data[] = {
+ 0x00, 0x14, 0x1c, 0x26, 0x2a, 0x2e, 0x34, 0x37, 0x3a, 0x3f, 0x42, 0x44,
+ 0x48, 0x4a, 0x4c, 0x50,
+ 0x52, 0x53, 0x57, 0x58, 0x5c, 0x5d, 0x5f, 0x62, 0x63, 0x64, 0x67, 0x68,
+ 0x6a, 0x6c, 0x6e, 0x6f,
+ 0x71, 0x72, 0x74, 0x76, 0x77, 0x78, 0x7a, 0x7c, 0x7e, 0x7f, 0x80, 0x82,
+ 0x83, 0x84, 0x86, 0x87,
+ 0x88, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x91, 0x92, 0x93, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9b,
+ 0x9b, 0x9c, 0x9e, 0x9f, 0x9f, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab,
+ 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb6,
+ 0xb8, 0xb8, 0xb9, 0xba,
+ 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc5, 0xc6, 0xc7, 0xc8,
+ 0xc9, 0xc9, 0xca, 0xcb, 0xcc, 0xcc, 0xce, 0xce, 0xcf, 0xd0, 0xd1, 0xd2,
+ 0xd2, 0xd3, 0xd4, 0xd5,
+ 0xd5, 0xd6, 0xd7, 0xd7, 0xd9, 0xd9, 0xda, 0xdb, 0xdb, 0xdc, 0xdd, 0xdd,
+ 0xdf, 0xdf, 0xe0, 0xe1,
+ 0xe1, 0xe2, 0xe3, 0xe3, 0xe4, 0xe5, 0xe5, 0xe6, 0xe7, 0xe7, 0xe8, 0xe9,
+ 0xe9, 0xea, 0xeb, 0xeb,
+ 0xec, 0xed, 0xed, 0xee, 0xef, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf3,
+ 0xf4, 0xf5, 0xf5, 0xf6,
+ 0xf7, 0xf7, 0xf8, 0xf9, 0xfa, 0xfa, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe,
+ 0xfe, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff
+};
+
+/* size=0x0100 */
+/* gamma table */
+static byte cp2155_gamma_greenblue_data[] = {
+ 0x00, 0x14, 0x1c, 0x21, 0x26, 0x2a, 0x2e, 0x31, 0x34, 0x37, 0x3a, 0x3d,
+ 0x3f, 0x42, 0x44, 0x46,
+ 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x53, 0x55, 0x57, 0x58, 0x5a, 0x5c,
+ 0x5d, 0x5f, 0x60, 0x62,
+ 0x63, 0x64, 0x66, 0x67, 0x68, 0x6a, 0x6b, 0x6c, 0x6e, 0x6f, 0x70, 0x71,
+ 0x72, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7a, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
+ 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
+ 0x93, 0x94, 0x95, 0x96,
+ 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac,
+ 0xac, 0xad, 0xae, 0xaf,
+ 0xaf, 0xb0, 0xb1, 0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb7,
+ 0xb8, 0xb8, 0xb9, 0xba,
+ 0xba, 0xbb, 0xbc, 0xbc, 0xbd, 0xbe, 0xbe, 0xbf, 0xc0, 0xc0, 0xc1, 0xc1,
+ 0xc2, 0xc3, 0xc3, 0xc4,
+ 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc8, 0xc8, 0xc9, 0xc9, 0xca, 0xcb, 0xcb,
+ 0xcc, 0xcc, 0xcd, 0xce,
+ 0xce, 0xcf, 0xcf, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0xd3, 0xd3, 0xd4, 0xd5,
+ 0xd5, 0xd6, 0xd6, 0xd7,
+ 0xd7, 0xd8, 0xd9, 0xd9, 0xda, 0xda, 0xdb, 0xdb, 0xdc, 0xdc, 0xdd, 0xdd,
+ 0xde, 0xdf, 0xdf, 0xe0,
+ 0xe0, 0xe1, 0xe1, 0xe2, 0xe2, 0xe3, 0xe3, 0xe4, 0xe4, 0xe5, 0xe5, 0xe6,
+ 0xe6, 0xe7, 0xe7, 0xe8,
+ 0xe8, 0xe9, 0xe9, 0xea, 0xea, 0xeb, 0xeb, 0xec, 0xec, 0xed, 0xed, 0xee,
+ 0xee, 0xef, 0xef, 0xf0,
+ 0xf0, 0xf1, 0xf1, 0xf2, 0xf2, 0xf3, 0xf3, 0xf4, 0xf4, 0xf5, 0xf5, 0xf6,
+ 0xf6, 0xf7, 0xf7, 0xf8,
+ 0xf8, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfc, 0xfc, 0xfd, 0xfd,
+ 0xfe, 0xfe, 0xff, 0xff
+};
+
+/* size=0x01f4 */
+static byte cp2155_slope09_back[] = {
+ 0x80, 0x25, 0x00, 0x25, 0x84, 0x24, 0x0b, 0x24, 0x96, 0x23, 0x23, 0x23,
+ 0xb3, 0x22, 0x46, 0x22,
+ 0xdb, 0x21, 0x73, 0x21, 0x0e, 0x21, 0xab, 0x20, 0x4a, 0x20, 0xeb, 0x1f,
+ 0x8f, 0x1f, 0x34, 0x1f,
+ 0xdc, 0x1e, 0x85, 0x1e, 0x31, 0x1e, 0xde, 0x1d, 0x8d, 0x1d, 0x3e, 0x1d,
+ 0xf0, 0x1c, 0xa4, 0x1c,
+ 0x59, 0x1c, 0x10, 0x1c, 0xc9, 0x1b, 0x83, 0x1b, 0x3e, 0x1b, 0xfa, 0x1a,
+ 0xb8, 0x1a, 0x77, 0x1a,
+ 0x38, 0x1a, 0xf9, 0x19, 0xbc, 0x19, 0x80, 0x19, 0x44, 0x19, 0x0a, 0x19,
+ 0xd1, 0x18, 0x99, 0x18,
+ 0x62, 0x18, 0x2c, 0x18, 0xf7, 0x17, 0xc3, 0x17, 0x8f, 0x17, 0x5d, 0x17,
+ 0x2b, 0x17, 0xfa, 0x16,
+ 0xca, 0x16, 0x9b, 0x16, 0x6c, 0x16, 0x3e, 0x16, 0x11, 0x16, 0xe5, 0x15,
+ 0xb9, 0x15, 0x8e, 0x15,
+ 0x64, 0x15, 0x3a, 0x15, 0x11, 0x15, 0xe9, 0x14, 0xc1, 0x14, 0x9a, 0x14,
+ 0x73, 0x14, 0x4d, 0x14,
+ 0x27, 0x14, 0x02, 0x14, 0xde, 0x13, 0xba, 0x13, 0x96, 0x13, 0x74, 0x13,
+ 0x51, 0x13, 0x2f, 0x13,
+ 0x0d, 0x13, 0xec, 0x12, 0xcc, 0x12, 0xab, 0x12, 0x8c, 0x12, 0x6c, 0x12,
+ 0x4d, 0x12, 0x2f, 0x12,
+ 0x11, 0x12, 0xf3, 0x11, 0xd5, 0x11, 0xb8, 0x11, 0x9c, 0x11, 0x80, 0x11,
+ 0x64, 0x11, 0x48, 0x11,
+ 0x2d, 0x11, 0x12, 0x11, 0xf7, 0x10, 0xdd, 0x10, 0xc3, 0x10, 0xa9, 0x10,
+ 0x90, 0x10, 0x77, 0x10,
+ 0x5e, 0x10, 0x46, 0x10, 0x2e, 0x10, 0x16, 0x10, 0xfe, 0x0f, 0xe7, 0x0f,
+ 0xd0, 0x0f, 0xb9, 0x0f,
+ 0xa2, 0x0f, 0x8c, 0x0f, 0x76, 0x0f, 0x60, 0x0f, 0x4b, 0x0f, 0x35, 0x0f,
+ 0x20, 0x0f, 0x0b, 0x0f,
+ 0xf7, 0x0e, 0xe2, 0x0e, 0xce, 0x0e, 0xba, 0x0e, 0xa6, 0x0e, 0x92, 0x0e,
+ 0x7f, 0x0e, 0x6c, 0x0e,
+ 0x59, 0x0e, 0x46, 0x0e, 0x33, 0x0e, 0x21, 0x0e, 0x0f, 0x0e, 0xfd, 0x0d,
+ 0xeb, 0x0d, 0xd9, 0x0d,
+ 0xc8, 0x0d, 0xb6, 0x0d, 0xa5, 0x0d, 0x94, 0x0d, 0x83, 0x0d, 0x73, 0x0d,
+ 0x62, 0x0d, 0x52, 0x0d,
+ 0x41, 0x0d, 0x31, 0x0d, 0x22, 0x0d, 0x12, 0x0d, 0x02, 0x0d, 0xf3, 0x0c,
+ 0xe3, 0x0c, 0xd4, 0x0c,
+ 0xc5, 0x0c, 0xb6, 0x0c, 0xa7, 0x0c, 0x99, 0x0c, 0x8a, 0x0c, 0x7c, 0x0c,
+ 0x6e, 0x0c, 0x60, 0x0c,
+ 0x52, 0x0c, 0x44, 0x0c, 0x36, 0x0c, 0x28, 0x0c, 0x1b, 0x0c, 0x0d, 0x0c,
+ 0x00, 0x0c, 0xf3, 0x0b,
+ 0xe6, 0x0b, 0xd9, 0x0b, 0xcc, 0x0b, 0xbf, 0x0b, 0xb3, 0x0b, 0xa6, 0x0b,
+ 0x9a, 0x0b, 0x8e, 0x0b,
+ 0x81, 0x0b, 0x75, 0x0b, 0x69, 0x0b, 0x5d, 0x0b, 0x52, 0x0b, 0x46, 0x0b,
+ 0x3a, 0x0b, 0x2f, 0x0b,
+ 0x23, 0x0b, 0x18, 0x0b, 0x0d, 0x0b, 0x02, 0x0b, 0xf6, 0x0a, 0xeb, 0x0a,
+ 0xe1, 0x0a, 0xd6, 0x0a,
+ 0xcb, 0x0a, 0xc0, 0x0a, 0xb6, 0x0a, 0xab, 0x0a, 0xa1, 0x0a, 0x97, 0x0a,
+ 0x8c, 0x0a, 0x82, 0x0a,
+ 0x78, 0x0a, 0x6e, 0x0a, 0x64, 0x0a, 0x5a, 0x0a, 0x50, 0x0a, 0x47, 0x0a,
+ 0x3d, 0x0a, 0x33, 0x0a,
+ 0x2a, 0x0a, 0x20, 0x0a, 0x17, 0x0a, 0x0e, 0x0a, 0x04, 0x0a, 0xfb, 0x09,
+ 0xf2, 0x09, 0xe9, 0x09,
+ 0xe0, 0x09, 0xd7, 0x09, 0xce, 0x09, 0xc6, 0x09, 0xbd, 0x09, 0xb4, 0x09,
+ 0xab, 0x09, 0xa3, 0x09,
+ 0x9a, 0x09, 0x92, 0x09, 0x8a, 0x09, 0x81, 0x09, 0x79, 0x09, 0x71, 0x09,
+ 0x69, 0x09, 0x61, 0x09,
+ 0x59, 0x09, 0x51, 0x09, 0x49, 0x09, 0x41, 0x09, 0x39, 0x09, 0x31, 0x09,
+ 0x29, 0x09, 0x22, 0x09,
+ 0x1a, 0x09, 0x12, 0x09, 0x0b, 0x09, 0x03, 0x09, 0xfc, 0x08, 0xf5, 0x08,
+ 0xed, 0x08, 0xe6, 0x08,
+ 0xdf, 0x08, 0xd8, 0x08, 0xd0, 0x08, 0xc9, 0x08, 0xc2, 0x08, 0xbb, 0x08,
+ 0xb4, 0x08, 0xad, 0x08,
+ 0xa6, 0x08, 0xa0, 0x08
+};
+
+/* size=0x0018 */
+static byte cp2155_slope10_back[] = {
+ 0x80, 0x25, 0xc0, 0x1c, 0x4f, 0x17, 0x9a, 0x13, 0xe9, 0x10, 0xde, 0x0e,
+ 0x44, 0x0d, 0xfa, 0x0b,
+ 0xea, 0x0a, 0x07, 0x0a, 0x46, 0x09, 0xa0, 0x08
+};
+
+static void
+cp2155_block2 (int fd, unsigned int addr)
+{
+ DBG (1, "cp2155_block2 %06x\n", addr);
+ cp2155_block1 (fd, 0x16, addr, cp2155_gamma_red_data, 0x0100);
+}
+
+static void
+cp2155_block3 (int fd, unsigned int addr)
+{
+ DBG (1, "cp2155_block3 %06x\n", addr);
+ cp2155_block1 (fd, 0x16, addr, cp2155_gamma_greenblue_data, 0x0100);
+}
+
+static void
+cp2155_set_slope (int fd, unsigned int addr, byte * data, size_t size)
+{
+/*
+ DBG (1, "cp2155_set_slope %06x %04lx\n", addr, (u_long) size);
+*/
+ cp2155_block1 (fd, 0x14, addr, data, size);
+}
+
+/* size=0x0075 */
+static byte cp2155_set_regs_data6[] = {
+ 0x00, 0x00, 0x00, 0x69, 0x00, 0xe8, 0x1d, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x2e, 0x00, 0x04,
+ 0x04, 0xf8, 0x07, 0x32, 0x32, 0x32, 0x32, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x02,
+ 0x00, 0x03, 0x15, 0x15, 0x15, 0x15, 0x04, 0x07, 0x29, 0x29, 0x09, 0x09,
+ 0x02, 0x06, 0x12, 0x12,
+ 0x03, 0x05, 0x05, 0x03, 0x05, 0x41, 0x61, 0x21, 0x21, 0x25, 0x25, 0x25,
+ 0x40, 0x40, 0x40, 0x06,
+ 0x40, 0x06, 0x00, 0x36, 0xd0, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x83,
+ 0x7c, 0x02, 0x1c, 0x9c,
+ 0x38, 0x28, 0x28, 0x27, 0x27, 0x25, 0x25, 0x21, 0x21, 0x1c, 0x1c, 0x16,
+ 0x16, 0x0f, 0x0f, 0x08,
+ 0x08, 0x00, 0x00, 0x08, 0x08, 0x0f, 0x0f, 0x16, 0x16, 0x1c, 0x1c, 0x21,
+ 0x21, 0x25, 0x25, 0x27,
+ 0x27, 0x02, 0x02, 0x22, 0x00
+};
+
+/* size=0x0075 */
+static byte cp2155_set_regs_nr[] = {
+ 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0xa0, 0xa1, 0xa2, 0xa3, 0x64, 0x65,
+ 0x61, 0x62, 0x63, 0x50,
+ 0x50, 0x90, 0x51, 0x5a, 0x5b, 0x5c, 0x5d, 0x52, 0x53, 0x54, 0x55, 0x56,
+ 0x57, 0x58, 0x59, 0x5e,
+ 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x60, 0x50, 0x51, 0x81, 0x81, 0x82, 0x82,
+ 0x83, 0x84, 0x80, 0x80,
+ 0xb0, 0x10, 0x10, 0x9b, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x12, 0x13, 0x16, 0x21,
+ 0x22, 0x20, 0x1d, 0x1e, 0x1f, 0x66, 0x67, 0x68, 0x1a, 0x1b, 0x1c, 0x15,
+ 0x14, 0x17, 0x43, 0x44,
+ 0x45, 0x23, 0x33, 0x24, 0x34, 0x25, 0x35, 0x26, 0x36, 0x27, 0x37, 0x28,
+ 0x38, 0x29, 0x39, 0x2a,
+ 0x3a, 0x2b, 0x3b, 0x2c, 0x3c, 0x2d, 0x3d, 0x2e, 0x3e, 0x2f, 0x3f, 0x30,
+ 0x40, 0x31, 0x41, 0x32,
+ 0x42, 0xca, 0xca, 0xca, 0x18
+};
+
+static void
+cp2155_set_regs (int fd, byte * data)
+{
+ DBG (1, "cp2155_set_regs\n");
+ int i;
+
+ for (i = 0; i < 0x0075; i++)
+ {
+ if (cp2155_set_regs_nr[i] != 0x90)
+ {
+ cp2155_set (fd, cp2155_set_regs_nr[i], data[i]);
+ }
+ }
+}
+
+static void
+cp2155_block5 (int fd, byte v001)
+{
+ DBG (1, "cp2155_block5 %02x\n", v001);
+ cp2155_set (fd, 0x90, 0xd8);
+ cp2155_set (fd, 0x90, 0xd8);
+ cp2155_set (fd, 0xb0, v001);
+}
+
+static void
+cp2155_block6 (int fd, byte v001, byte v002)
+{
+ DBG (1, "cp2155_block6 %02x %02x\n", v001, v002);
+ cp2155_set (fd, 0x80, v001);
+ cp2155_set (fd, 0x11, v002);
+}
+
+static void
+cp2155_block8 (int fd)
+{
+ DBG (1, "cp2155_block8\n");
+ cp2155_set (fd, 0x04, 0x0c);
+ cp2155_set (fd, 0x05, 0x00);
+ cp2155_set (fd, 0x06, 0x00);
+}
+
+static void
+cp2155_set_gamma (int fd)
+{
+ DBG (1, "cp2155_set_gamma\n");
+/* gamma tables */
+ cp2155_block3 (fd, 0x000000);
+ cp2155_block3 (fd, 0x000100);
+ cp2155_block3 (fd, 0x000200);
+}
+
+static void
+cp2155_set_gamma600 (int fd)
+{
+ DBG (1, "cp2155_set_gamma\n");
+/* gamma tables */
+ cp2155_block2 (fd, 0x000000);
+ cp2155_block3 (fd, 0x000100);
+ cp2155_block3 (fd, 0x000200);
+}
+
+static void
+cp2155_motor (int fd, byte v001, byte v002)
+{
+ DBG (1, "cp2155_motor %02x %02x\n", v001, v002);
+ cp2155_set (fd, 0x10, v001);
+ cp2155_set (fd, 0x11, v002);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0x03, 0x01); /* starts motor */
+}
+
+void
+make_buf (size_t count, unsigned char *buf)
+{
+ size_t i = 4;
+ int hiword = 62756;
+ int loword = 20918;
+ unsigned char hihi = (hiword >> 8) & 0xff;
+ unsigned char hilo = (hiword) & 0xff;
+ unsigned char lohi = (loword >> 8) & 0xff;
+ unsigned char lolo = (loword) & 0xff;
+ buf[0] = 0x04;
+ buf[1] = 0x70;
+ buf[2] = (count - 4) & 0xff;
+ buf[3] = ((count - 4) >> 8) & 0xff;
+ while (i < count)
+ {
+ buf[i] = hilo;
+ i++;
+ buf[i] = hihi;
+ i++;
+ buf[i] = lolo;
+ i++;
+ buf[i] = lohi;
+ i++;
+ }
+}
+
+void
+big_write (int fd, size_t count, unsigned char *buf)
+{
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x51);
+ cp2155_set (fd, 0x73, 0x70);
+ cp2155_set (fd, 0x74, 0x00);
+ cp2155_set (fd, 0x75, 0x00);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ make_buf (count, buf);
+ sanei_usb_write_bulk (fd, buf, &count);
+
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x51);
+ cp2155_set (fd, 0x73, 0x70);
+ cp2155_set (fd, 0x74, 0x00);
+ cp2155_set (fd, 0x75, 0xb0);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ sanei_usb_write_bulk (fd, buf, &count);
+
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x51);
+ cp2155_set (fd, 0x73, 0x70);
+ cp2155_set (fd, 0x74, 0x01);
+ cp2155_set (fd, 0x75, 0x60);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ sanei_usb_write_bulk (fd, buf, &count);
+
+}
+
+void
+startblob0075 (CANON_Handle * chndl, unsigned char *buf)
+{
+
+ int fd;
+ fd = chndl->fd;
+ size_t count;
+
+ cp2155_set (fd, 0x90, 0xd8);
+ cp2155_set (fd, 0x90, 0xd8);
+ cp2155_set (fd, 0xb0, 0x03);
+ cp2155_set (fd, 0x07, 0x00);
+ cp2155_set (fd, 0x07, 0x00);
+ cp2155_set (fd, 0x08, chndl->value_08);
+ cp2155_set (fd, 0x09, chndl->value_09);
+ cp2155_set (fd, 0x0a, chndl->value_0a);
+ cp2155_set (fd, 0x0b, chndl->value_0b);
+ cp2155_set (fd, 0xa0, 0x1d);
+ cp2155_set (fd, 0xa1, 0x00);
+ cp2155_set (fd, 0xa2, 0x06);
+ cp2155_set (fd, 0xa3, 0x70);
+ cp2155_set (fd, 0x64, 0x00);
+ cp2155_set (fd, 0x65, 0x00);
+ cp2155_set (fd, 0x61, 0x00);
+ cp2155_set (fd, 0x62, 0x2e);
+ cp2155_set (fd, 0x63, 0x00);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x51, chndl->value_51);
+ cp2155_set (fd, 0x5a, 0x32);
+ cp2155_set (fd, 0x5b, 0x32);
+ cp2155_set (fd, 0x5c, 0x32);
+ cp2155_set (fd, 0x5d, 0x32);
+ cp2155_set (fd, 0x52, 0x09);
+ cp2155_set (fd, 0x53, 0x5a);
+ cp2155_set (fd, 0x54, 0x06);
+ cp2155_set (fd, 0x55, 0x08);
+ cp2155_set (fd, 0x56, 0x05);
+ cp2155_set (fd, 0x57, 0x5f);
+ cp2155_set (fd, 0x58, 0xa9);
+ cp2155_set (fd, 0x59, 0xce);
+ cp2155_set (fd, 0x5e, 0x02);
+ cp2155_set (fd, 0x5f, 0x00);
+ cp2155_set (fd, 0x5f, 0x03);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x51, chndl->value_51);
+ cp2155_set (fd, 0x81, 0x29);
+ cp2155_set (fd, 0x81, 0x29);
+ cp2155_set (fd, 0x82, 0x09);
+ cp2155_set (fd, 0x82, 0x09);
+ cp2155_set (fd, 0x83, 0x02);
+ cp2155_set (fd, 0x84, 0x06);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0xb0, 0x0b);
+
+ big_write (fd, 20852, buf);
+
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x9b, 0x03);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x11, 0xc1);
+ cp2155_set (fd, 0x11, 0xc1);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x12, 0x40);
+ cp2155_set (fd, 0x13, 0x40);
+ cp2155_set (fd, 0x16, 0x40);
+ cp2155_set (fd, 0x21, 0x06);
+ cp2155_set (fd, 0x22, 0x40);
+ cp2155_set (fd, 0x20, 0x06);
+ cp2155_set (fd, 0x1d, 0x00);
+ cp2155_set (fd, 0x1e, 0x00);
+ cp2155_set (fd, 0x1f, 0xf0);
+ cp2155_set (fd, 0x66, 0x00);
+ cp2155_set (fd, 0x67, chndl->value_67);
+ cp2155_set (fd, 0x68, chndl->value_68);
+ cp2155_set (fd, 0x1a, 0x00);
+ cp2155_set (fd, 0x1b, 0x00);
+ cp2155_set (fd, 0x1c, 0x02);
+ cp2155_set (fd, 0x15, 0x83);
+ cp2155_set (fd, 0x14, 0x7c);
+ cp2155_set (fd, 0x17, 0x02);
+ cp2155_set (fd, 0x43, 0x1c);
+ cp2155_set (fd, 0x44, 0x9c);
+ cp2155_set (fd, 0x45, 0x38);
+ cp2155_set (fd, 0x23, 0x28);
+ cp2155_set (fd, 0x33, 0x28);
+ cp2155_set (fd, 0x24, 0x27);
+ cp2155_set (fd, 0x34, 0x27);
+ cp2155_set (fd, 0x25, 0x25);
+ cp2155_set (fd, 0x35, 0x25);
+ cp2155_set (fd, 0x26, 0x21);
+ cp2155_set (fd, 0x36, 0x21);
+ cp2155_set (fd, 0x27, 0x1c);
+ cp2155_set (fd, 0x37, 0x1c);
+ cp2155_set (fd, 0x28, 0x16);
+ cp2155_set (fd, 0x38, 0x16);
+ cp2155_set (fd, 0x29, 0x0f);
+ cp2155_set (fd, 0x39, 0x0f);
+ cp2155_set (fd, 0x2a, 0x08);
+ cp2155_set (fd, 0x3a, 0x08);
+ cp2155_set (fd, 0x2b, 0x00);
+ cp2155_set (fd, 0x3b, 0x00);
+ cp2155_set (fd, 0x2c, 0x08);
+ cp2155_set (fd, 0x3c, 0x08);
+ cp2155_set (fd, 0x2d, 0x0f);
+ cp2155_set (fd, 0x3d, 0x0f);
+ cp2155_set (fd, 0x2e, 0x16);
+ cp2155_set (fd, 0x3e, 0x16);
+ cp2155_set (fd, 0x2f, 0x1c);
+ cp2155_set (fd, 0x3f, 0x1c);
+ cp2155_set (fd, 0x30, 0x21);
+ cp2155_set (fd, 0x40, 0x21);
+ cp2155_set (fd, 0x31, 0x25);
+ cp2155_set (fd, 0x41, 0x25);
+ cp2155_set (fd, 0x32, 0x27);
+ cp2155_set (fd, 0x42, 0x27);
+ cp2155_set (fd, 0xca, 0x01);
+ cp2155_set (fd, 0xca, 0x01);
+ cp2155_set (fd, 0xca, 0x11);
+ cp2155_set (fd, 0x18, 0x00);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x01);
+ cp2155_set (fd, 0x73, 0x00);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x00);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x00\x01\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000020,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000030,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000040,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000050,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000060,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\xf0\x23\x80\x22\x2c\x21",
+ 16);
+ memcpy (buf + 0x00000070,
+ "\xf1\x1f\xcd\x1e\xbd\x1d\xc0\x1c\xd2\x1b\xf4\x1a\x22\x1a\x5e\x19",
+ 16);
+ memcpy (buf + 0x00000080,
+ "\xa4\x18\xf5\x17\x4f\x17\xb2\x16\x1d\x16\x90\x15\x09\x15\x89\x14",
+ 16);
+ memcpy (buf + 0x00000090,
+ "\x0e\x14\x9a\x13\x2a\x13\xc0\x12\x59\x12\xf8\x11\x9a\x11\x3f\x11",
+ 16);
+ memcpy (buf + 0x000000a0,
+ "\xe9\x10\x96\x10\x46\x10\xf8\x0f\xae\x0f\x66\x0f\x21\x0f\xde\x0e",
+ 16);
+ memcpy (buf + 0x000000b0,
+ "\x9e\x0e\x60\x0e\x23\x0e\xe9\x0d\xb0\x0d\x7a\x0d\x44\x0d\x11\x0d",
+ 16);
+ memcpy (buf + 0x000000c0,
+ "\xdf\x0c\xaf\x0c\x80\x0c\x52\x0c\x25\x0c\xfa\x0b\xd0\x0b\xa7\x0b",
+ 16);
+ memcpy (buf + 0x000000d0,
+ "\x80\x0b\x59\x0b\x33\x0b\x0e\x0b\xea\x0a\xc8\x0a\xa5\x0a\x84\x0a",
+ 16);
+ memcpy (buf + 0x000000e0,
+ "\x64\x0a\x44\x0a\x25\x0a\x07\x0a\xe9\x09\xcd\x09\xb0\x09\x95\x09",
+ 16);
+ memcpy (buf + 0x000000f0,
+ "\x7a\x09\x60\x09\x46\x09\x2c\x09\x14\x09\xfc\x08\xe4\x08\xcd\x08",
+ 16);
+ memcpy (buf + 0x00000100, "\xb6\x08\xa0\x08", 4);
+ count = 260;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x01);
+ cp2155_set (fd, 0x73, 0x00);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x02);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x00\x01\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000020,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000030,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000040,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000050,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000060,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\xf0\x23\x80\x22\x2c\x21",
+ 16);
+ memcpy (buf + 0x00000070,
+ "\xf1\x1f\xcd\x1e\xbd\x1d\xc0\x1c\xd2\x1b\xf4\x1a\x22\x1a\x5e\x19",
+ 16);
+ memcpy (buf + 0x00000080,
+ "\xa4\x18\xf5\x17\x4f\x17\xb2\x16\x1d\x16\x90\x15\x09\x15\x89\x14",
+ 16);
+ memcpy (buf + 0x00000090,
+ "\x0e\x14\x9a\x13\x2a\x13\xc0\x12\x59\x12\xf8\x11\x9a\x11\x3f\x11",
+ 16);
+ memcpy (buf + 0x000000a0,
+ "\xe9\x10\x96\x10\x46\x10\xf8\x0f\xae\x0f\x66\x0f\x21\x0f\xde\x0e",
+ 16);
+ memcpy (buf + 0x000000b0,
+ "\x9e\x0e\x60\x0e\x23\x0e\xe9\x0d\xb0\x0d\x7a\x0d\x44\x0d\x11\x0d",
+ 16);
+ memcpy (buf + 0x000000c0,
+ "\xdf\x0c\xaf\x0c\x80\x0c\x52\x0c\x25\x0c\xfa\x0b\xd0\x0b\xa7\x0b",
+ 16);
+ memcpy (buf + 0x000000d0,
+ "\x80\x0b\x59\x0b\x33\x0b\x0e\x0b\xea\x0a\xc8\x0a\xa5\x0a\x84\x0a",
+ 16);
+ memcpy (buf + 0x000000e0,
+ "\x64\x0a\x44\x0a\x25\x0a\x07\x0a\xe9\x09\xcd\x09\xb0\x09\x95\x09",
+ 16);
+ memcpy (buf + 0x000000f0,
+ "\x7a\x09\x60\x09\x46\x09\x2c\x09\x14\x09\xfc\x08\xe4\x08\xcd\x08",
+ 16);
+ memcpy (buf + 0x00000100, "\xb6\x08\xa0\x08", 4);
+ count = 260;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x04);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x18\x00\x80\x25\xc0\x1c\x4f\x17\x9a\x13\xe9\x10\xde\x0e",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x44\x0d\xfa\x0b\xea\x0a\x07\x0a\x46\x09\xa0\x08\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000020, "\x80\x25\x80\x25", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x01);
+ cp2155_set (fd, 0x73, 0x00);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x06);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x00\x01\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000020,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000030,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000040,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000050,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000060,
+ "\x80\x25\x80\x25\x80\x25\x80\x25\x80\x25\xf0\x23\x80\x22\x2c\x21",
+ 16);
+ memcpy (buf + 0x00000070,
+ "\xf1\x1f\xcd\x1e\xbd\x1d\xc0\x1c\xd2\x1b\xf4\x1a\x22\x1a\x5e\x19",
+ 16);
+ memcpy (buf + 0x00000080,
+ "\xa4\x18\xf5\x17\x4f\x17\xb2\x16\x1d\x16\x90\x15\x09\x15\x89\x14",
+ 16);
+ memcpy (buf + 0x00000090,
+ "\x0e\x14\x9a\x13\x2a\x13\xc0\x12\x59\x12\xf8\x11\x9a\x11\x3f\x11",
+ 16);
+ memcpy (buf + 0x000000a0,
+ "\xe9\x10\x96\x10\x46\x10\xf8\x0f\xae\x0f\x66\x0f\x21\x0f\xde\x0e",
+ 16);
+ memcpy (buf + 0x000000b0,
+ "\x9e\x0e\x60\x0e\x23\x0e\xe9\x0d\xb0\x0d\x7a\x0d\x44\x0d\x11\x0d",
+ 16);
+ memcpy (buf + 0x000000c0,
+ "\xdf\x0c\xaf\x0c\x80\x0c\x52\x0c\x25\x0c\xfa\x0b\xd0\x0b\xa7\x0b",
+ 16);
+ memcpy (buf + 0x000000d0,
+ "\x80\x0b\x59\x0b\x33\x0b\x0e\x0b\xea\x0a\xc8\x0a\xa5\x0a\x84\x0a",
+ 16);
+ memcpy (buf + 0x000000e0,
+ "\x64\x0a\x44\x0a\x25\x0a\x07\x0a\xe9\x09\xcd\x09\xb0\x09\x95\x09",
+ 16);
+ memcpy (buf + 0x000000f0,
+ "\x7a\x09\x60\x09\x46\x09\x2c\x09\x14\x09\xfc\x08\xe4\x08\xcd\x08",
+ 16);
+ memcpy (buf + 0x00000100, "\xb6\x08\xa0\x08", 4);
+ count = 260;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x08);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x18\x00\x80\x25\xc0\x1c\x4f\x17\x9a\x13\xe9\x10\xde\x0e",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x44\x0d\xfa\x0b\xea\x0a\x07\x0a\x46\x09\xa0\x08\x80\x25\x80\x25",
+ 16);
+ memcpy (buf + 0x00000020, "\x80\x25\x80\x25", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x9b, 0x02);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x11, 0x91);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0x03, 0x01);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x18);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x10);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+
+}
+
+void
+startblob0150 (CANON_Handle * chndl, unsigned char *buf)
+{
+
+ int fd;
+ fd = chndl->fd;
+ size_t count;
+
+ cp2155_set (fd, 0x90, 0xd8);
+ cp2155_set (fd, 0x90, 0xd8);
+ cp2155_set (fd, 0xb0, 0x02);
+ cp2155_set (fd, 0x07, 0x00);
+ cp2155_set (fd, 0x07, 0x00);
+ cp2155_set (fd, 0x08, chndl->value_08);
+ cp2155_set (fd, 0x09, chndl->value_09);
+ cp2155_set (fd, 0x0a, chndl->value_0a);
+ cp2155_set (fd, 0x0b, chndl->value_0b);
+ cp2155_set (fd, 0xa0, 0x1d);
+ cp2155_set (fd, 0xa1, 0x00);
+ cp2155_set (fd, 0xa2, 0x0c);
+ cp2155_set (fd, 0xa3, 0xd0);
+ cp2155_set (fd, 0x64, 0x00);
+ cp2155_set (fd, 0x65, 0x00);
+ cp2155_set (fd, 0x61, 0x00);
+ cp2155_set (fd, 0x62, 0x1e);
+ cp2155_set (fd, 0x63, 0xa0);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x51, chndl->value_51);
+ cp2155_set (fd, 0x5a, 0x32);
+ cp2155_set (fd, 0x5b, 0x32);
+ cp2155_set (fd, 0x5c, 0x32);
+ cp2155_set (fd, 0x5d, 0x32);
+ cp2155_set (fd, 0x52, 0x09);
+ cp2155_set (fd, 0x53, 0x5a);
+ cp2155_set (fd, 0x54, 0x06);
+ cp2155_set (fd, 0x55, 0x08);
+ cp2155_set (fd, 0x56, 0x05);
+ cp2155_set (fd, 0x57, 0x5f);
+ cp2155_set (fd, 0x58, 0xa9);
+ cp2155_set (fd, 0x59, 0xce);
+ cp2155_set (fd, 0x5e, 0x02);
+ cp2155_set (fd, 0x5f, 0x00);
+ cp2155_set (fd, 0x5f, 0x03);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x51, chndl->value_51);
+ cp2155_set (fd, 0x81, 0x29);
+ cp2155_set (fd, 0x81, 0x29);
+ cp2155_set (fd, 0x82, 0x09);
+ cp2155_set (fd, 0x82, 0x09);
+ cp2155_set (fd, 0x83, 0x02);
+ cp2155_set (fd, 0x84, 0x06);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0xb0, 0x0a);
+
+ big_write (fd, 20852, buf);
+
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x9b, 0x03);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x12, 0x40);
+ cp2155_set (fd, 0x13, 0x40);
+ cp2155_set (fd, 0x16, 0x40);
+ cp2155_set (fd, 0x21, 0x06);
+ cp2155_set (fd, 0x22, 0x40);
+ cp2155_set (fd, 0x20, 0x06);
+ cp2155_set (fd, 0x1d, 0x00);
+ cp2155_set (fd, 0x1e, 0x00);
+ cp2155_set (fd, 0x1f, 0x04);
+ cp2155_set (fd, 0x66, 0x00);
+ cp2155_set (fd, 0x67, chndl->value_67);
+ cp2155_set (fd, 0x68, chndl->value_68);
+ cp2155_set (fd, 0x1a, 0x00);
+ cp2155_set (fd, 0x1b, 0x00);
+ cp2155_set (fd, 0x1c, 0x02);
+ cp2155_set (fd, 0x15, 0x84);
+ cp2155_set (fd, 0x14, 0x7c);
+ cp2155_set (fd, 0x17, 0x02);
+ cp2155_set (fd, 0x43, 0x1c);
+ cp2155_set (fd, 0x44, 0x9c);
+ cp2155_set (fd, 0x45, 0x38);
+ cp2155_set (fd, 0x23, 0x28);
+ cp2155_set (fd, 0x33, 0x28);
+ cp2155_set (fd, 0x24, 0x27);
+ cp2155_set (fd, 0x34, 0x27);
+ cp2155_set (fd, 0x25, 0x25);
+ cp2155_set (fd, 0x35, 0x25);
+ cp2155_set (fd, 0x26, 0x21);
+ cp2155_set (fd, 0x36, 0x21);
+ cp2155_set (fd, 0x27, 0x1c);
+ cp2155_set (fd, 0x37, 0x1c);
+ cp2155_set (fd, 0x28, 0x16);
+ cp2155_set (fd, 0x38, 0x16);
+ cp2155_set (fd, 0x29, 0x0f);
+ cp2155_set (fd, 0x39, 0x0f);
+ cp2155_set (fd, 0x2a, 0x08);
+ cp2155_set (fd, 0x3a, 0x08);
+ cp2155_set (fd, 0x2b, 0x00);
+ cp2155_set (fd, 0x3b, 0x00);
+ cp2155_set (fd, 0x2c, 0x08);
+ cp2155_set (fd, 0x3c, 0x08);
+ cp2155_set (fd, 0x2d, 0x0f);
+ cp2155_set (fd, 0x3d, 0x0f);
+ cp2155_set (fd, 0x2e, 0x16);
+ cp2155_set (fd, 0x3e, 0x16);
+ cp2155_set (fd, 0x2f, 0x1c);
+ cp2155_set (fd, 0x3f, 0x1c);
+ cp2155_set (fd, 0x30, 0x21);
+ cp2155_set (fd, 0x40, 0x21);
+ cp2155_set (fd, 0x31, 0x25);
+ cp2155_set (fd, 0x41, 0x25);
+ cp2155_set (fd, 0x32, 0x27);
+ cp2155_set (fd, 0x42, 0x27);
+ cp2155_set (fd, 0xca, 0x01);
+ cp2155_set (fd, 0xca, 0x01);
+ cp2155_set (fd, 0xca, 0x11);
+ cp2155_set (fd, 0x18, 0x00);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x01);
+ cp2155_set (fd, 0x73, 0x00);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x00);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x00\x01\x80\x25\xd7\x24\x35\x24\x98\x23\x00\x23\x6d\x22",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\xdf\x21\x56\x21\xd1\x20\x50\x20\xd2\x1f\x59\x1f\xe3\x1e\x70\x1e",
+ 16);
+ memcpy (buf + 0x00000020,
+ "\x01\x1e\x95\x1d\x2c\x1d\xc6\x1c\x62\x1c\x02\x1c\xa3\x1b\x47\x1b",
+ 16);
+ memcpy (buf + 0x00000030,
+ "\xee\x1a\x97\x1a\x42\x1a\xef\x19\x9e\x19\x4f\x19\x02\x19\xb7\x18",
+ 16);
+ memcpy (buf + 0x00000040,
+ "\x6d\x18\x25\x18\xdf\x17\x9a\x17\x57\x17\x16\x17\xd6\x16\x97\x16",
+ 16);
+ memcpy (buf + 0x00000050,
+ "\x59\x16\x1d\x16\xe2\x15\xa8\x15\x70\x15\x38\x15\x02\x15\xcd\x14",
+ 16);
+ memcpy (buf + 0x00000060,
+ "\x99\x14\x66\x14\x33\x14\x02\x14\xd2\x13\xa2\x13\x74\x13\x46\x13",
+ 16);
+ memcpy (buf + 0x00000070,
+ "\x19\x13\xed\x12\xc2\x12\x98\x12\x6e\x12\x45\x12\x1d\x12\xf5\x11",
+ 16);
+ memcpy (buf + 0x00000080,
+ "\xce\x11\xa8\x11\x82\x11\x5d\x11\x39\x11\x15\x11\xf2\x10\xcf\x10",
+ 16);
+ memcpy (buf + 0x00000090,
+ "\xad\x10\x8b\x10\x6a\x10\x4a\x10\x2a\x10\x0a\x10\xeb\x0f\xcc\x0f",
+ 16);
+ memcpy (buf + 0x000000a0,
+ "\xae\x0f\x90\x0f\x73\x0f\x56\x0f\x3a\x0f\x1e\x0f\x02\x0f\xe7\x0e",
+ 16);
+ memcpy (buf + 0x000000b0,
+ "\xcc\x0e\xb2\x0e\x97\x0e\x7e\x0e\x64\x0e\x4b\x0e\x32\x0e\x1a\x0e",
+ 16);
+ memcpy (buf + 0x000000c0,
+ "\x02\x0e\xea\x0d\xd3\x0d\xbc\x0d\xa5\x0d\x8e\x0d\x78\x0d\x62\x0d",
+ 16);
+ memcpy (buf + 0x000000d0,
+ "\x4d\x0d\x37\x0d\x22\x0d\x0d\x0d\xf8\x0c\xe4\x0c\xd0\x0c\xbc\x0c",
+ 16);
+ memcpy (buf + 0x000000e0,
+ "\xa8\x0c\x95\x0c\x82\x0c\x6f\x0c\x5c\x0c\x4a\x0c\x37\x0c\x25\x0c",
+ 16);
+ memcpy (buf + 0x000000f0,
+ "\x14\x0c\x02\x0c\xf0\x0b\xdf\x0b\xce\x0b\xbd\x0b\xac\x0b\x9c\x0b",
+ 16);
+ memcpy (buf + 0x00000100, "\x8c\x0b\x7c\x0b", 4);
+ count = 260;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x01);
+ cp2155_set (fd, 0x73, 0x00);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x02);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x00\x01\x80\x25\xd7\x24\x35\x24\x98\x23\x00\x23\x6d\x22",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\xdf\x21\x56\x21\xd1\x20\x50\x20\xd2\x1f\x59\x1f\xe3\x1e\x70\x1e",
+ 16);
+ memcpy (buf + 0x00000020,
+ "\x01\x1e\x95\x1d\x2c\x1d\xc6\x1c\x62\x1c\x02\x1c\xa3\x1b\x47\x1b",
+ 16);
+ memcpy (buf + 0x00000030,
+ "\xee\x1a\x97\x1a\x42\x1a\xef\x19\x9e\x19\x4f\x19\x02\x19\xb7\x18",
+ 16);
+ memcpy (buf + 0x00000040,
+ "\x6d\x18\x25\x18\xdf\x17\x9a\x17\x57\x17\x16\x17\xd6\x16\x97\x16",
+ 16);
+ memcpy (buf + 0x00000050,
+ "\x59\x16\x1d\x16\xe2\x15\xa8\x15\x70\x15\x38\x15\x02\x15\xcd\x14",
+ 16);
+ memcpy (buf + 0x00000060,
+ "\x99\x14\x66\x14\x33\x14\x02\x14\xd2\x13\xa2\x13\x74\x13\x46\x13",
+ 16);
+ memcpy (buf + 0x00000070,
+ "\x19\x13\xed\x12\xc2\x12\x98\x12\x6e\x12\x45\x12\x1d\x12\xf5\x11",
+ 16);
+ memcpy (buf + 0x00000080,
+ "\xce\x11\xa8\x11\x82\x11\x5d\x11\x39\x11\x15\x11\xf2\x10\xcf\x10",
+ 16);
+ memcpy (buf + 0x00000090,
+ "\xad\x10\x8b\x10\x6a\x10\x4a\x10\x2a\x10\x0a\x10\xeb\x0f\xcc\x0f",
+ 16);
+ memcpy (buf + 0x000000a0,
+ "\xae\x0f\x90\x0f\x73\x0f\x56\x0f\x3a\x0f\x1e\x0f\x02\x0f\xe7\x0e",
+ 16);
+ memcpy (buf + 0x000000b0,
+ "\xcc\x0e\xb2\x0e\x97\x0e\x7e\x0e\x64\x0e\x4b\x0e\x32\x0e\x1a\x0e",
+ 16);
+ memcpy (buf + 0x000000c0,
+ "\x02\x0e\xea\x0d\xd3\x0d\xbc\x0d\xa5\x0d\x8e\x0d\x78\x0d\x62\x0d",
+ 16);
+ memcpy (buf + 0x000000d0,
+ "\x4d\x0d\x37\x0d\x22\x0d\x0d\x0d\xf8\x0c\xe4\x0c\xd0\x0c\xbc\x0c",
+ 16);
+ memcpy (buf + 0x000000e0,
+ "\xa8\x0c\x95\x0c\x82\x0c\x6f\x0c\x5c\x0c\x4a\x0c\x37\x0c\x25\x0c",
+ 16);
+ memcpy (buf + 0x000000f0,
+ "\x14\x0c\x02\x0c\xf0\x0b\xdf\x0b\xce\x0b\xbd\x0b\xac\x0b\x9c\x0b",
+ 16);
+ memcpy (buf + 0x00000100, "\x8c\x0b\x7c\x0b", 4);
+ count = 260;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x04);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x18\x00\x80\x25\x18\x1f\x8f\x1a\x2d\x17\x8f\x14\x79\x12",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\xc6\x10\x5b\x0f\x2a\x0e\x24\x0d\x41\x0c\x7c\x0b\xe3\x1e\x70\x1e",
+ 16);
+ memcpy (buf + 0x00000020, "\x01\x1e\x95\x1d", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x01);
+ cp2155_set (fd, 0x73, 0x00);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x06);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x00\x01\x80\x25\xd7\x24\x35\x24\x98\x23\x00\x23\x6d\x22",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\xdf\x21\x56\x21\xd1\x20\x50\x20\xd2\x1f\x59\x1f\xe3\x1e\x70\x1e",
+ 16);
+ memcpy (buf + 0x00000020,
+ "\x01\x1e\x95\x1d\x2c\x1d\xc6\x1c\x62\x1c\x02\x1c\xa3\x1b\x47\x1b",
+ 16);
+ memcpy (buf + 0x00000030,
+ "\xee\x1a\x97\x1a\x42\x1a\xef\x19\x9e\x19\x4f\x19\x02\x19\xb7\x18",
+ 16);
+ memcpy (buf + 0x00000040,
+ "\x6d\x18\x25\x18\xdf\x17\x9a\x17\x57\x17\x16\x17\xd6\x16\x97\x16",
+ 16);
+ memcpy (buf + 0x00000050,
+ "\x59\x16\x1d\x16\xe2\x15\xa8\x15\x70\x15\x38\x15\x02\x15\xcd\x14",
+ 16);
+ memcpy (buf + 0x00000060,
+ "\x99\x14\x66\x14\x33\x14\x02\x14\xd2\x13\xa2\x13\x74\x13\x46\x13",
+ 16);
+ memcpy (buf + 0x00000070,
+ "\x19\x13\xed\x12\xc2\x12\x98\x12\x6e\x12\x45\x12\x1d\x12\xf5\x11",
+ 16);
+ memcpy (buf + 0x00000080,
+ "\xce\x11\xa8\x11\x82\x11\x5d\x11\x39\x11\x15\x11\xf2\x10\xcf\x10",
+ 16);
+ memcpy (buf + 0x00000090,
+ "\xad\x10\x8b\x10\x6a\x10\x4a\x10\x2a\x10\x0a\x10\xeb\x0f\xcc\x0f",
+ 16);
+ memcpy (buf + 0x000000a0,
+ "\xae\x0f\x90\x0f\x73\x0f\x56\x0f\x3a\x0f\x1e\x0f\x02\x0f\xe7\x0e",
+ 16);
+ memcpy (buf + 0x000000b0,
+ "\xcc\x0e\xb2\x0e\x97\x0e\x7e\x0e\x64\x0e\x4b\x0e\x32\x0e\x1a\x0e",
+ 16);
+ memcpy (buf + 0x000000c0,
+ "\x02\x0e\xea\x0d\xd3\x0d\xbc\x0d\xa5\x0d\x8e\x0d\x78\x0d\x62\x0d",
+ 16);
+ memcpy (buf + 0x000000d0,
+ "\x4d\x0d\x37\x0d\x22\x0d\x0d\x0d\xf8\x0c\xe4\x0c\xd0\x0c\xbc\x0c",
+ 16);
+ memcpy (buf + 0x000000e0,
+ "\xa8\x0c\x95\x0c\x82\x0c\x6f\x0c\x5c\x0c\x4a\x0c\x37\x0c\x25\x0c",
+ 16);
+ memcpy (buf + 0x000000f0,
+ "\x14\x0c\x02\x0c\xf0\x0b\xdf\x0b\xce\x0b\xbd\x0b\xac\x0b\x9c\x0b",
+ 16);
+ memcpy (buf + 0x00000100, "\x8c\x0b\x7c\x0b", 4);
+ count = 260;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x08);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x18\x00\x80\x25\x18\x1f\x8f\x1a\x2d\x17\x8f\x14\x79\x12",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\xc6\x10\x5b\x0f\x2a\x0e\x24\x0d\x41\x0c\x7c\x0b\xe3\x1e\x70\x1e",
+ 16);
+ memcpy (buf + 0x00000020, "\x01\x1e\x95\x1d", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x9b, 0x02);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x11, 0x91);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0x03, 0x01);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x18);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x10);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+
+}
+
+void
+startblob0300 (CANON_Handle * chndl, unsigned char *buf)
+{
+
+ int fd;
+ fd = chndl->fd;
+ size_t count;
+
+ cp2155_set (fd, 0x90, 0xd8);
+ cp2155_set (fd, 0x90, 0xd8);
+ cp2155_set (fd, 0xb0, 0x01);
+ cp2155_set (fd, 0x07, 0x00);
+ cp2155_set (fd, 0x07, 0x00);
+ cp2155_set (fd, 0x08, chndl->value_08);
+ cp2155_set (fd, 0x09, chndl->value_09);
+ cp2155_set (fd, 0x0a, chndl->value_0a);
+ cp2155_set (fd, 0x0b, chndl->value_0b);
+ cp2155_set (fd, 0xa0, 0x1d);
+ cp2155_set (fd, 0xa1, 0x00);
+ cp2155_set (fd, 0xa2, 0x19);
+ cp2155_set (fd, 0xa3, 0x30);
+ cp2155_set (fd, 0x64, 0x00);
+ cp2155_set (fd, 0x65, 0x00);
+ cp2155_set (fd, 0x61, 0x00);
+ cp2155_set (fd, 0x62, 0x2a);
+ cp2155_set (fd, 0x63, 0x80);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x51, chndl->value_51);
+ cp2155_set (fd, 0x5a, 0x32);
+ cp2155_set (fd, 0x5b, 0x32);
+ cp2155_set (fd, 0x5c, 0x32);
+ cp2155_set (fd, 0x5d, 0x32);
+ cp2155_set (fd, 0x52, 0x09);
+ cp2155_set (fd, 0x53, 0x5a);
+ cp2155_set (fd, 0x54, 0x06);
+ cp2155_set (fd, 0x55, 0x08);
+ cp2155_set (fd, 0x56, 0x05);
+ cp2155_set (fd, 0x57, 0x5f);
+ cp2155_set (fd, 0x58, 0xa9);
+ cp2155_set (fd, 0x59, 0xce);
+ cp2155_set (fd, 0x5e, 0x02);
+ cp2155_set (fd, 0x5f, 0x00);
+ cp2155_set (fd, 0x5f, 0x03);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x51, chndl->value_51);
+ cp2155_set (fd, 0x81, 0x29);
+ cp2155_set (fd, 0x81, 0x29);
+ cp2155_set (fd, 0x82, 0x09);
+ cp2155_set (fd, 0x82, 0x09);
+ cp2155_set (fd, 0x83, 0x02);
+ cp2155_set (fd, 0x84, 0x06);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0xb0, 0x09);
+
+ big_write (fd, 20852, buf);
+
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x9b, 0x01);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x12, 0x0c);
+ cp2155_set (fd, 0x13, 0x0c);
+ cp2155_set (fd, 0x16, 0x0c);
+ cp2155_set (fd, 0x21, 0x06);
+ cp2155_set (fd, 0x22, 0x0c);
+ cp2155_set (fd, 0x20, 0x06);
+ cp2155_set (fd, 0x1d, 0x00);
+ cp2155_set (fd, 0x1e, 0x00);
+ cp2155_set (fd, 0x1f, 0x04);
+ cp2155_set (fd, 0x66, 0x00);
+ cp2155_set (fd, 0x67, chndl->value_67);
+ cp2155_set (fd, 0x68, chndl->value_68);
+ cp2155_set (fd, 0x1a, 0x00);
+ cp2155_set (fd, 0x1b, 0x00);
+ cp2155_set (fd, 0x1c, 0x02);
+ cp2155_set (fd, 0x15, 0x83);
+ cp2155_set (fd, 0x14, 0x7c);
+ cp2155_set (fd, 0x17, 0x02);
+ cp2155_set (fd, 0x43, 0x1c);
+ cp2155_set (fd, 0x44, 0x9c);
+ cp2155_set (fd, 0x45, 0x38);
+ cp2155_set (fd, 0x23, 0x14);
+ cp2155_set (fd, 0x33, 0x14);
+ cp2155_set (fd, 0x24, 0x14);
+ cp2155_set (fd, 0x34, 0x14);
+ cp2155_set (fd, 0x25, 0x14);
+ cp2155_set (fd, 0x35, 0x14);
+ cp2155_set (fd, 0x26, 0x14);
+ cp2155_set (fd, 0x36, 0x14);
+ cp2155_set (fd, 0x27, 0x14);
+ cp2155_set (fd, 0x37, 0x14);
+ cp2155_set (fd, 0x28, 0x14);
+ cp2155_set (fd, 0x38, 0x14);
+ cp2155_set (fd, 0x29, 0x14);
+ cp2155_set (fd, 0x39, 0x14);
+ cp2155_set (fd, 0x2a, 0x14);
+ cp2155_set (fd, 0x3a, 0x14);
+ cp2155_set (fd, 0x2b, 0x14);
+ cp2155_set (fd, 0x3b, 0x14);
+ cp2155_set (fd, 0x2c, 0x14);
+ cp2155_set (fd, 0x3c, 0x14);
+ cp2155_set (fd, 0x2d, 0x14);
+ cp2155_set (fd, 0x3d, 0x14);
+ cp2155_set (fd, 0x2e, 0x14);
+ cp2155_set (fd, 0x3e, 0x14);
+ cp2155_set (fd, 0x2f, 0x14);
+ cp2155_set (fd, 0x3f, 0x14);
+ cp2155_set (fd, 0x30, 0x14);
+ cp2155_set (fd, 0x40, 0x14);
+ cp2155_set (fd, 0x31, 0x14);
+ cp2155_set (fd, 0x41, 0x14);
+ cp2155_set (fd, 0x32, 0x14);
+ cp2155_set (fd, 0x42, 0x14);
+ cp2155_set (fd, 0xca, 0x00);
+ cp2155_set (fd, 0xca, 0x00);
+ cp2155_set (fd, 0xca, 0x00);
+ cp2155_set (fd, 0x18, 0x00);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x30);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x00);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x30\x00\x80\x25\x36\x25\xee\x24\xa8\x24\x62\x24\x1d\x24",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\xd9\x23\x96\x23\x54\x23\x13\x23\xd3\x22\x94\x22\x56\x22\x19\x22",
+ 16);
+ memcpy (buf + 0x00000020,
+ "\xdc\x21\xa1\x21\x66\x21\x2c\x21\xf3\x20\xba\x20\x82\x20\x4b\x20",
+ 16);
+ memcpy (buf + 0x00000030, "\x15\x20\xe0\x1f", 4);
+ count = 52;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x30);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x02);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x30\x00\x80\x25\x36\x25\xee\x24\xa8\x24\x62\x24\x1d\x24",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\xd9\x23\x96\x23\x54\x23\x13\x23\xd3\x22\x94\x22\x56\x22\x19\x22",
+ 16);
+ memcpy (buf + 0x00000020,
+ "\xdc\x21\xa1\x21\x66\x21\x2c\x21\xf3\x20\xba\x20\x82\x20\x4b\x20",
+ 16);
+ memcpy (buf + 0x00000030, "\x15\x20\xe0\x1f", 4);
+ count = 52;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x04);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x18\x00\x80\x25\xe8\x24\x55\x24\xc7\x23\x3d\x23\xb7\x22",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x35\x22\xb6\x21\x3c\x21\xc4\x20\x50\x20\xe0\x1f\x56\x22\x19\x22",
+ 16);
+ memcpy (buf + 0x00000020, "\xdc\x21\xa1\x21", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x30);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x06);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x30\x00\x80\x25\x36\x25\xee\x24\xa8\x24\x62\x24\x1d\x24",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\xd9\x23\x96\x23\x54\x23\x13\x23\xd3\x22\x94\x22\x56\x22\x19\x22",
+ 16);
+ memcpy (buf + 0x00000020,
+ "\xdc\x21\xa1\x21\x66\x21\x2c\x21\xf3\x20\xba\x20\x82\x20\x4b\x20",
+ 16);
+ memcpy (buf + 0x00000030, "\x15\x20\xe0\x1f", 4);
+ count = 52;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x08);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x18\x00\x80\x25\xe8\x24\x55\x24\xc7\x23\x3d\x23\xb7\x22",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x35\x22\xb6\x21\x3c\x21\xc4\x20\x50\x20\xe0\x1f\x56\x22\x19\x22",
+ 16);
+ memcpy (buf + 0x00000020, "\xdc\x21\xa1\x21", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x9b, 0x00);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x11, 0x91);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0x03, 0x01);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x18);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x10);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+
+}
+
+void
+startblob0600 (CANON_Handle * chndl, unsigned char *buf)
+{
+
+ int fd;
+ fd = chndl->fd;
+ size_t count;
+
+ cp2155_set (fd, 0x90, 0xd8);
+ cp2155_set (fd, 0x90, 0xd8);
+ cp2155_set (fd, 0xb0, 0x00);
+ cp2155_set (fd, 0x07, 0x00);
+ cp2155_set (fd, 0x07, 0x00);
+ cp2155_set (fd, 0x08, chndl->value_08);
+ cp2155_set (fd, 0x09, chndl->value_09);
+ cp2155_set (fd, 0x0a, chndl->value_0a);
+ cp2155_set (fd, 0x0b, chndl->value_0b);
+ cp2155_set (fd, 0xa0, 0x1d);
+ cp2155_set (fd, 0xa1, 0x00);
+ cp2155_set (fd, 0xa2, 0x77);
+ cp2155_set (fd, 0xa3, 0xb0);
+ cp2155_set (fd, 0x64, 0x00);
+ cp2155_set (fd, 0x65, 0x00);
+ cp2155_set (fd, 0x61, 0x00);
+ cp2155_set (fd, 0x62, 0x15);
+ cp2155_set (fd, 0x63, 0xe0);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x51, chndl->value_51);
+ cp2155_set (fd, 0x5a, 0x32);
+ cp2155_set (fd, 0x5b, 0x32);
+ cp2155_set (fd, 0x5c, 0x32);
+ cp2155_set (fd, 0x5d, 0x32);
+ cp2155_set (fd, 0x52, 0x07);
+ cp2155_set (fd, 0x53, 0xd0);
+ cp2155_set (fd, 0x54, 0x07);
+ cp2155_set (fd, 0x55, 0xd0);
+ cp2155_set (fd, 0x56, 0x07);
+ cp2155_set (fd, 0x57, 0xd0);
+ cp2155_set (fd, 0x58, 0x00);
+ cp2155_set (fd, 0x59, 0x01);
+ cp2155_set (fd, 0x5e, 0x02);
+ cp2155_set (fd, 0x5f, 0x00);
+ cp2155_set (fd, 0x5f, 0x03);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x51, chndl->value_51);
+ cp2155_set (fd, 0x81, 0x29);
+ cp2155_set (fd, 0x81, 0x29);
+ cp2155_set (fd, 0x82, 0x09);
+ cp2155_set (fd, 0x82, 0x09);
+ cp2155_set (fd, 0x83, 0x02);
+ cp2155_set (fd, 0x84, 0x06);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0xb0, 0x00);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x9b, 0x01);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x11, 0x83);
+ cp2155_set (fd, 0x11, 0x83);
+ cp2155_set (fd, 0x11, 0xc3);
+ cp2155_set (fd, 0x11, 0xc3);
+ cp2155_set (fd, 0x11, 0xc3);
+ cp2155_set (fd, 0x11, 0xc1);
+ cp2155_set (fd, 0x11, 0xc1);
+ cp2155_set (fd, 0x12, 0x12);
+ cp2155_set (fd, 0x13, 0x00);
+ cp2155_set (fd, 0x16, 0x12);
+ cp2155_set (fd, 0x21, 0x06);
+ cp2155_set (fd, 0x22, 0x12);
+ cp2155_set (fd, 0x20, 0x06);
+ cp2155_set (fd, 0x1d, 0x00);
+ cp2155_set (fd, 0x1e, 0x00);
+ cp2155_set (fd, 0x1f, 0x04);
+ cp2155_set (fd, 0x66, 0x00);
+ cp2155_set (fd, 0x67, chndl->value_67);
+ cp2155_set (fd, 0x68, chndl->value_68);
+ cp2155_set (fd, 0x1a, 0x00);
+ cp2155_set (fd, 0x1b, 0x00);
+ cp2155_set (fd, 0x1c, 0x02);
+ cp2155_set (fd, 0x15, 0x01);
+ cp2155_set (fd, 0x14, 0x01);
+ cp2155_set (fd, 0x17, 0x01);
+ cp2155_set (fd, 0x43, 0x1c);
+ cp2155_set (fd, 0x44, 0x9c);
+ cp2155_set (fd, 0x45, 0x38);
+ cp2155_set (fd, 0x23, 0x14);
+ cp2155_set (fd, 0x33, 0x14);
+ cp2155_set (fd, 0x24, 0x14);
+ cp2155_set (fd, 0x34, 0x14);
+ cp2155_set (fd, 0x25, 0x14);
+ cp2155_set (fd, 0x35, 0x14);
+ cp2155_set (fd, 0x26, 0x14);
+ cp2155_set (fd, 0x36, 0x14);
+ cp2155_set (fd, 0x27, 0x14);
+ cp2155_set (fd, 0x37, 0x14);
+ cp2155_set (fd, 0x28, 0x14);
+ cp2155_set (fd, 0x38, 0x14);
+ cp2155_set (fd, 0x29, 0x14);
+ cp2155_set (fd, 0x39, 0x14);
+ cp2155_set (fd, 0x2a, 0x14);
+ cp2155_set (fd, 0x3a, 0x14);
+ cp2155_set (fd, 0x2b, 0x14);
+ cp2155_set (fd, 0x3b, 0x14);
+ cp2155_set (fd, 0x2c, 0x14);
+ cp2155_set (fd, 0x3c, 0x14);
+ cp2155_set (fd, 0x2d, 0x14);
+ cp2155_set (fd, 0x3d, 0x14);
+ cp2155_set (fd, 0x2e, 0x14);
+ cp2155_set (fd, 0x3e, 0x14);
+ cp2155_set (fd, 0x2f, 0x14);
+ cp2155_set (fd, 0x3f, 0x14);
+ cp2155_set (fd, 0x30, 0x14);
+ cp2155_set (fd, 0x40, 0x14);
+ cp2155_set (fd, 0x31, 0x14);
+ cp2155_set (fd, 0x41, 0x14);
+ cp2155_set (fd, 0x32, 0x14);
+ cp2155_set (fd, 0x42, 0x14);
+ cp2155_set (fd, 0xca, 0x00);
+ cp2155_set (fd, 0xca, 0x00);
+ cp2155_set (fd, 0xca, 0x00);
+ cp2155_set (fd, 0x18, 0x00);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x50);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x00);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x0000,
+ "\x04\x70\x50\x00\x80\x25\x58\x25\x32\x25\x0b\x25\xe5\x24\xc0\x24",
+ 16);
+ memcpy (buf + 0x0010,
+ "\x9a\x24\x75\x24\x50\x24\x2b\x24\x07\x24\xe3\x23\xbf\x23\x9c\x23",
+ 16);
+ memcpy (buf + 0x0020,
+ "\x79\x23\x56\x23\x33\x23\x11\x23\xee\x22\xcd\x22\xab\x22\x8a\x22",
+ 16);
+ memcpy (buf + 0x0030,
+ "\x68\x22\x48\x22\x27\x22\x07\x22\xe6\x21\xc7\x21\xa7\x21\x87\x21",
+ 16);
+ memcpy (buf + 0x0040,
+ "\x68\x21\x49\x21\x2a\x21\x0c\x21\xee\x20\xd0\x20\x00\x00\x00\x00",
+ 16);
+ memcpy (buf + 0x0050, "\x00\x00\x00\x00", 4);
+ count = 84;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x50);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x02);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x0000,
+ "\x04\x70\x50\x00\x80\x25\x58\x25\x32\x25\x0b\x25\xe5\x24\xc0\x24",
+ 16);
+ memcpy (buf + 0x0010,
+ "\x9a\x24\x75\x24\x50\x24\x2b\x24\x07\x24\xe3\x23\xbf\x23\x9c\x23",
+ 16);
+ memcpy (buf + 0x0020,
+ "\x79\x23\x56\x23\x33\x23\x11\x23\xee\x22\xcd\x22\xab\x22\x8a\x22",
+ 16);
+ memcpy (buf + 0x0030,
+ "\x68\x22\x48\x22\x27\x22\x07\x22\xe6\x21\xc7\x21\xa7\x21\x87\x21",
+ 16);
+ memcpy (buf + 0x0040,
+ "\x68\x21\x49\x21\x2a\x21\x0c\x21\xee\x20\xd0\x20\x00\x00\x00\x00",
+ 16);
+ memcpy (buf + 0x0050, "\x00\x00\x00\x00", 4);
+ count = 84;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x04);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x0000,
+ "\x04\x70\x20\x00\x80\x25\x04\x25\x8c\x24\x18\x24\xa5\x23\x36\x23",
+ 16);
+ memcpy (buf + 0x0010,
+ "\xca\x22\x60\x22\xf8\x21\x93\x21\x30\x21\xd0\x20\x00\x00\x00\x00",
+ 16);
+ memcpy (buf + 0x0020, "\x00\x00\x00\x00", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x50);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x06);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x0000,
+ "\x04\x70\x50\x00\x80\x25\x58\x25\x32\x25\x0b\x25\xe5\x24\xc0\x24",
+ 16);
+ memcpy (buf + 0x0010,
+ "\x9a\x24\x75\x24\x50\x24\x2b\x24\x07\x24\xe3\x23\xbf\x23\x9c\x23",
+ 16);
+ memcpy (buf + 0x0020,
+ "\x79\x23\x56\x23\x33\x23\x11\x23\xee\x22\xcd\x22\xab\x22\x8a\x22",
+ 16);
+ memcpy (buf + 0x0030,
+ "\x68\x22\x48\x22\x27\x22\x07\x22\xe6\x21\xc7\x21\xa7\x21\x87\x21",
+ 16);
+ memcpy (buf + 0x0040,
+ "\x68\x21\x49\x21\x2a\x21\x0c\x21\xee\x20\xd0\x20\x00\x00\x00\x00",
+ 16);
+ memcpy (buf + 0x0050, "\x00\x00\x00\x00", 4);
+ count = 84;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x08);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x0000,
+ "\x04\x70\x20\x00\x80\x25\x04\x25\x8c\x24\x18\x24\xa5\x23\x36\x23",
+ 16);
+ memcpy (buf + 0x0010,
+ "\xca\x22\x60\x22\xf8\x21\x93\x21\x30\x21\xd0\x20\x00\x00\x00\x00",
+ 16);
+ memcpy (buf + 0x0020, "\x00\x00\x00\x00", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x9b, 0x00);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x11, 0xd1);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0x03, 0x01);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x18);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x10);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+
+}
+
+void
+startblob1200 (CANON_Handle * chndl, unsigned char *buf)
+{
+
+ int fd;
+ fd = chndl->fd;
+ size_t count;
+
+ cp2155_set (fd, 0x90, 0xc8);
+ cp2155_set (fd, 0x90, 0xe8);
+ cp2155_set (fd, 0xb0, 0x00);
+ cp2155_set (fd, 0x07, 0x00);
+ cp2155_set (fd, 0x07, 0x00);
+ cp2155_set (fd, 0x08, chndl->value_08);
+ cp2155_set (fd, 0x09, chndl->value_09);
+ cp2155_set (fd, 0x0a, chndl->value_0a);
+ cp2155_set (fd, 0x0b, chndl->value_0b);
+ cp2155_set (fd, 0xa0, 0x1d);
+ cp2155_set (fd, 0xa1, 0x00);
+ cp2155_set (fd, 0xa2, 0x63);
+ cp2155_set (fd, 0xa3, 0xd0);
+ cp2155_set (fd, 0x64, 0x00);
+ cp2155_set (fd, 0x65, 0x00);
+ cp2155_set (fd, 0x61, 0x00);
+ cp2155_set (fd, 0x62, 0xaa);
+ cp2155_set (fd, 0x63, 0x00);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x51, chndl->value_51);
+ cp2155_set (fd, 0x5a, 0x32);
+ cp2155_set (fd, 0x5b, 0x32);
+ cp2155_set (fd, 0x5c, 0x32);
+ cp2155_set (fd, 0x5d, 0x32);
+ cp2155_set (fd, 0x52, 0x11);
+ cp2155_set (fd, 0x53, 0x50);
+ cp2155_set (fd, 0x54, 0x0c);
+ cp2155_set (fd, 0x55, 0x01);
+ cp2155_set (fd, 0x56, 0x0a);
+ cp2155_set (fd, 0x57, 0xae);
+ cp2155_set (fd, 0x58, 0xa9);
+ cp2155_set (fd, 0x59, 0xce);
+ cp2155_set (fd, 0x5e, 0x02);
+ cp2155_set (fd, 0x5f, 0x00);
+ cp2155_set (fd, 0x5f, 0x03);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x50, 0x04);
+ cp2155_set (fd, 0x51, chndl->value_51);
+ cp2155_set (fd, 0x81, 0x29);
+ cp2155_set (fd, 0x81, 0x29);
+ cp2155_set (fd, 0x82, 0x09);
+ cp2155_set (fd, 0x82, 0x09);
+ cp2155_set (fd, 0x83, 0x02);
+ cp2155_set (fd, 0x84, 0x06);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0xb0, 0x08);
+
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0xa1);
+ cp2155_set (fd, 0x73, 0xa0);
+ cp2155_set (fd, 0x74, 0x00);
+ cp2155_set (fd, 0x75, 0x00);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ count = 41380;
+ make_buf (count, buf);
+ sanei_usb_write_bulk (fd, buf, &count);
+
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0xa1);
+ cp2155_set (fd, 0x73, 0xa0);
+ cp2155_set (fd, 0x74, 0x00);
+ cp2155_set (fd, 0x75, 0xb0);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ sanei_usb_write_bulk (fd, buf, &count);
+
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0xa1);
+ cp2155_set (fd, 0x73, 0xa0);
+ cp2155_set (fd, 0x74, 0x01);
+ cp2155_set (fd, 0x75, 0x60);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ sanei_usb_write_bulk (fd, buf, &count);
+
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x9b, 0x01);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x11, 0x81);
+ cp2155_set (fd, 0x12, 0x06);
+ cp2155_set (fd, 0x13, 0x06);
+ cp2155_set (fd, 0x16, 0x06);
+ cp2155_set (fd, 0x21, 0x06);
+ cp2155_set (fd, 0x22, 0x06);
+ cp2155_set (fd, 0x20, 0x06);
+ cp2155_set (fd, 0x1d, 0x00);
+ cp2155_set (fd, 0x1e, 0x00);
+ cp2155_set (fd, 0x1f, 0x04);
+ cp2155_set (fd, 0x66, 0x00);
+ cp2155_set (fd, 0x67, chndl->value_67);
+ cp2155_set (fd, 0x68, chndl->value_68);
+ cp2155_set (fd, 0x1a, 0x00);
+ cp2155_set (fd, 0x1b, 0x00);
+ cp2155_set (fd, 0x1c, 0x02);
+ cp2155_set (fd, 0x15, 0x80);
+ cp2155_set (fd, 0x14, 0x7c);
+ cp2155_set (fd, 0x17, 0x01);
+ cp2155_set (fd, 0x43, 0x1c);
+ cp2155_set (fd, 0x44, 0x9c);
+ cp2155_set (fd, 0x45, 0x38);
+ cp2155_set (fd, 0x23, 0x14);
+ cp2155_set (fd, 0x33, 0x14);
+ cp2155_set (fd, 0x24, 0x14);
+ cp2155_set (fd, 0x34, 0x14);
+ cp2155_set (fd, 0x25, 0x12);
+ cp2155_set (fd, 0x35, 0x12);
+ cp2155_set (fd, 0x26, 0x11);
+ cp2155_set (fd, 0x36, 0x11);
+ cp2155_set (fd, 0x27, 0x0e);
+ cp2155_set (fd, 0x37, 0x0e);
+ cp2155_set (fd, 0x28, 0x0b);
+ cp2155_set (fd, 0x38, 0x0b);
+ cp2155_set (fd, 0x29, 0x08);
+ cp2155_set (fd, 0x39, 0x08);
+ cp2155_set (fd, 0x2a, 0x04);
+ cp2155_set (fd, 0x3a, 0x04);
+ cp2155_set (fd, 0x2b, 0x00);
+ cp2155_set (fd, 0x3b, 0x00);
+ cp2155_set (fd, 0x2c, 0x04);
+ cp2155_set (fd, 0x3c, 0x04);
+ cp2155_set (fd, 0x2d, 0x08);
+ cp2155_set (fd, 0x3d, 0x08);
+ cp2155_set (fd, 0x2e, 0x0b);
+ cp2155_set (fd, 0x3e, 0x0b);
+ cp2155_set (fd, 0x2f, 0x0e);
+ cp2155_set (fd, 0x3f, 0x0e);
+ cp2155_set (fd, 0x30, 0x11);
+ cp2155_set (fd, 0x40, 0x11);
+ cp2155_set (fd, 0x31, 0x12);
+ cp2155_set (fd, 0x41, 0x12);
+ cp2155_set (fd, 0x32, 0x14);
+ cp2155_set (fd, 0x42, 0x14);
+ cp2155_set (fd, 0xca, 0x00);
+ cp2155_set (fd, 0xca, 0x00);
+ cp2155_set (fd, 0xca, 0x00);
+ cp2155_set (fd, 0x18, 0x01);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x00);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x18\x00\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\x00\x00\x00",
+ 16);
+ memcpy (buf + 0x00000020, "\x00\x00\x00\x00", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x02);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x18\x00\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\x00\x00\x00",
+ 16);
+ memcpy (buf + 0x00000020, "\x00\x00\x00\x00", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x04);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x18\x00\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\x00\x00\x00",
+ 16);
+ memcpy (buf + 0x00000020, "\x00\x00\x00\x00", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x06);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x18\x00\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\x00\x00\x00",
+ 16);
+ memcpy (buf + 0x00000020, "\x00\x00\x00\x00", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x14);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x20);
+ cp2155_set (fd, 0x74, 0x03);
+ cp2155_set (fd, 0x75, 0x08);
+ cp2155_set (fd, 0x76, 0x00);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+ memcpy (buf + 0x00000000,
+ "\x04\x70\x18\x00\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff",
+ 16);
+ memcpy (buf + 0x00000010,
+ "\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\x00\x00\x00",
+ 16);
+ memcpy (buf + 0x00000020, "\x00\x00\x00\x00", 4);
+ count = 36;
+ sanei_usb_write_bulk (fd, buf, &count);
+ cp2155_set (fd, 0x9b, 0x00);
+ cp2155_set (fd, 0x10, 0x05);
+ cp2155_set (fd, 0x11, 0x91);
+ cp2155_set (fd, 0x60, 0x15);
+ cp2155_set (fd, 0x80, 0x12);
+ cp2155_set (fd, 0x03, 0x01);
+ cp2155_set (fd, 0x71, 0x01);
+ cp2155_set (fd, 0x0230, 0x11);
+ cp2155_set (fd, 0x71, 0x18);
+ cp2155_set (fd, 0x72, 0x00);
+ cp2155_set (fd, 0x73, 0x10);
+ cp2155_set (fd, 0x0239, 0x40);
+ cp2155_set (fd, 0x0238, 0x89);
+ cp2155_set (fd, 0x023c, 0x2f);
+ cp2155_set (fd, 0x0264, 0x20);
+
+}
+
+void
+send_start_blob (CANON_Handle * chndl)
+{
+ unsigned char buf[0xf000];
+
+ int fd;
+ fd = chndl->fd;
+
+/* value_51: lamp colors
+ bit 0 set: red on, bit 1 set: green on, bit 2 set: blue on
+ all bits off: no scan is made
+*/
+ chndl->value_51 = 0x07;
+
+ switch (chndl->val[opt_resolution].w)
+ {
+ case 75:
+ chndl->value_67 = 0x0a; /* 3*7300/8 */
+ chndl->value_68 = 0xb1;
+ break;
+ case 150:
+ chndl->value_67 = 0x15; /* 3*7300/4 */
+ chndl->value_68 = 0x63;
+ break;
+ case 300:
+ chndl->value_67 = 0x2a; /* 3*7300/2 */
+ chndl->value_68 = 0xc6;
+ break;
+ case 600:
+ chndl->value_67 = 0x55; /* 3*7300 */
+ chndl->value_68 = 0x8c;
+ break;
+ case 1200:
+ chndl->value_67 = 0xab; /* 6*7300 */
+ chndl->value_68 = 0x18;
+ }
+
+ cp2155_block6 (fd, 0x12, 0x83);
+ cp2155_set (fd, 0x90, 0xf8);
+ cp2155_block6 (fd, 0x12, 0x83);
+/* start preparing real scan */
+ cp2155_set (fd, 0x01, 0x29);
+ cp2155_block8 (fd);
+ cp2155_set (fd, 0x01, 0x29);
+ cp2155_set_gamma (fd);
+
+ switch (chndl->val[opt_resolution].w)
+ {
+ case 75:
+ startblob0075 (chndl, buf);
+ break;
+ case 150:
+ startblob0150 (chndl, buf);
+ break;
+ case 300:
+ startblob0300 (chndl, buf);
+ break;
+ case 600:
+ cp2155_set_gamma600 (fd);
+ startblob0600 (chndl, buf);
+ break;
+ case 1200:
+ startblob1200 (chndl, buf);
+ }
+}
+
+/* Wait until data ready */
+static long
+wait_for_data (CANON_Handle * chndl)
+{
+ int fd;
+ fd = chndl->fd;
+ time_t start_time = time (NULL);
+ long size;
+ byte value;
+
+ DBG (12, "waiting...\n");
+
+ while (1)
+ {
+ size = 0;
+ cp2155_get (fd, 0x46, &value);
+ DBG (1, "home sensor: %02x\n", value);
+ if (value == 0)
+ {
+ send_start_blob (chndl);
+ cp2155_get (fd, 0x46, &value);
+ DBG (1, "home sensor: %02x\n", value);
+ }
+
+ if (cp2155_get (fd, 0xa5, &value) != SANE_STATUS_GOOD)
+ {
+ return -1;
+ }
+
+ size += value;
+
+ if (cp2155_get (fd, 0xa6, &value) != SANE_STATUS_GOOD)
+ {
+ return -1;
+ }
+
+ size <<= 8;
+ size += value;
+
+ if (cp2155_get (fd, 0xa7, &value) != SANE_STATUS_GOOD)
+ {
+ return -1;
+ }
+
+ size <<= 8;
+ size += value;
+
+ if (size != 0)
+ {
+ return 2 * size;
+ }
+
+ /* Give it 5 seconds */
+ if ((time (NULL) - start_time) > 5)
+ {
+ DBG (1, "wait_for_data: timed out (%ld)\n", size);
+ return -1;
+ }
+
+ usleep (1 * MSEC);
+ }
+}
+
+static void
+go_home_without_wait (int fd)
+{
+ byte value;
+ cp2155_get (fd, 0x46, &value);
+ if (value == 0x08)
+ {
+ return;
+ }
+ cp2155_block6 (fd, 0x12, 0xc1);
+ cp2155_set (fd, 0x01, 0x29);
+ cp2155_block8 (fd);
+ cp2155_set (fd, 0x01, 0x29);
+ cp2155_set_gamma (fd);
+ cp2155_block5 (fd, 0x03);
+ cp2155_set_regs (fd, cp2155_set_regs_data6);
+ cp2155_set_slope (fd, 0x030000, cp2155_slope09_back, 0x01f4);
+ cp2155_set_slope (fd, 0x030200, cp2155_slope09_back, 0x01f4);
+ cp2155_set_slope (fd, 0x030400, cp2155_slope10_back, 0x0018);
+ cp2155_set_slope (fd, 0x030600, cp2155_slope09_back, 0x01f4);
+ cp2155_set_slope (fd, 0x030800, cp2155_slope10_back, 0x0018);
+
+ cp2155_motor (fd, 0x05, 0x35);
+}
+
+
+static int
+go_home (int fd)
+{
+ byte value;
+ cp2155_get (fd, 0x46, &value);
+ if (value == 0x08)
+ {
+ return 0;
+ }
+
+ go_home_without_wait (fd);
+
+ while (1)
+ {
+ usleep (200 * MSEC);
+ cp2155_get (fd, 0x46, &value);
+ DBG (1, "home sensor: %02x\n", value);
+
+ if (value == 0x08)
+ {
+ break;
+ }
+ }
+ return 0;
+}
+
+
+/* Scanner init, called at calibration and scan time.
+ Returns:
+ 1 if this was the first time the scanner was plugged in,
+ 0 afterward, and
+ -1 on error. */
+
+static int
+init (CANON_Handle * chndl)
+{
+ int fd = chndl->fd;
+ byte value;
+ int result = 0;
+
+ cp2155_get (fd, 0xd0, &value);
+ /* Detect if scanner is plugged in */
+ if (value != 0x81 && value != 0x40)
+ {
+ DBG (0, "INIT: unexpected value: %x\n", value);
+ }
+
+ if (value == 0x00)
+ {
+ return -1;
+ }
+
+ cp2155_set (fd, 0x02, 0x01);
+ cp2155_set (fd, 0x02, 0x00);
+ cp2155_set (fd, 0x01, 0x00);
+ cp2155_set (fd, 0x01, 0x28);
+ cp2155_set (fd, 0x90, 0x4f);
+ cp2155_set (fd, 0x92, 0xff);
+ cp2155_set (fd, 0x93, 0x00);
+ cp2155_set (fd, 0x91, 0x1f);
+ cp2155_set (fd, 0x95, 0x1f);
+ cp2155_set (fd, 0x97, 0x1f);
+ cp2155_set (fd, 0x9b, 0x00);
+ cp2155_set (fd, 0x9c, 0x07);
+ cp2155_set (fd, 0x90, 0x4d);
+ cp2155_set (fd, 0x90, 0xcd);
+ cp2155_set (fd, 0x90, 0xcc);
+ cp2155_set (fd, 0x9b, 0x01);
+ cp2155_set (fd, 0xa0, 0x04);
+ cp2155_set (fd, 0xa0, 0x05);
+ cp2155_set (fd, 0x01, 0x28);
+ cp2155_set (fd, 0x04, 0x0c);
+ cp2155_set (fd, 0x05, 0x00);
+ cp2155_set (fd, 0x06, 0x00);
+ cp2155_set (fd, 0x98, 0x00);
+ cp2155_set (fd, 0x98, 0x00);
+ cp2155_set (fd, 0x98, 0x02);
+ cp2155_set (fd, 0x99, 0x28);
+ cp2155_set (fd, 0x9a, 0x03);
+ cp2155_set (fd, 0x80, 0x10);
+ cp2155_set (fd, 0x8d, 0x00);
+ cp2155_set (fd, 0x8d, 0x04);
+
+ cp2155_set (fd, 0x85, 0x00);
+ cp2155_set (fd, 0x87, 0x00);
+ cp2155_set (fd, 0x88, 0x70);
+
+ cp2155_set (fd, 0x85, 0x03);
+ cp2155_set (fd, 0x87, 0x00);
+ cp2155_set (fd, 0x88, 0x28);
+
+ cp2155_set (fd, 0x85, 0x06);
+ cp2155_set (fd, 0x87, 0x00);
+ cp2155_set (fd, 0x88, 0x28);
+
+
+ DBG (1, "INIT state: %0d\n", result);
+ return result;
+}
+
+/* Scan and save the resulting image as r,g,b non-interleaved PPM file */
+static SANE_Status
+preread (CANON_Handle * chndl, SANE_Byte * data, FILE * fp)
+{
+ SANE_Status status = SANE_STATUS_GOOD;
+
+ static byte linebuf[0x40000];
+ byte readbuf[0xf000];
+ int fd = chndl->fd;
+ long width = chndl->params.pixels_per_line;
+ /* set width to next multiple of 0x10 */
+ while ((width % 0x10) != 0xf)
+ {
+ width++;
+ }
+
+ width++;
+
+ byte *srcptr = readbuf;
+ static byte *dstptr = linebuf;
+ byte *endptr = linebuf + 3 * width; /* Red line + Green line + Blue line */
+ long datasize = 0;
+ static long line = 0;
+ size_t offset = 0;
+ size_t bytes_written;
+ static byte slot = 0;
+
+ /* Data coming back is "width" bytes Red data, width bytes Green,
+ width bytes Blue, repeat for "height" lines. */
+/* while (line < height) process one buffer from the scanner */
+ long startline = line;
+
+ if (line >= (chndl->y1) * chndl->val[opt_resolution].w / 600
+ + chndl->params.lines)
+ {
+ status = SANE_STATUS_EOF;
+ init (chndl);
+ line = 0;
+ slot = 0;
+ dstptr = linebuf;
+ return status;
+ }
+ datasize = wait_for_data (chndl);
+
+ if (datasize < 0)
+ {
+ DBG (1, "no data\n");
+ status = SANE_STATUS_EOF;
+ return status;
+ }
+
+ if (datasize > 0xf000)
+ {
+ datasize = 0xf000;
+ }
+
+ DBG (12, "scan line %ld %ld\n", line, datasize);
+
+ cp2155_set (fd, 0x72, (datasize >> 8) & 0xff);
+ cp2155_set (fd, 0x73, (datasize) & 0xff);
+
+ status = cp2155_read (fd, readbuf, datasize);
+
+ if (status != SANE_STATUS_GOOD)
+ {
+ status = SANE_STATUS_INVAL;
+ return status;
+ }
+
+ /* Contorsions to convert data from line-by-line RGB to byte-by-byte RGB,
+ without reading in the whole buffer first. One image line is
+ constructed in buffer linebuf and written to temp file if complete. */
+ int idx = 0;
+ srcptr = readbuf;
+
+ while (idx < datasize)
+ {
+ *dstptr = (byte) * srcptr;
+ idx++;
+ srcptr += 1;
+ dstptr += 3;
+
+ if (dstptr >= endptr) /* line of one color complete */
+ {
+ slot++; /* next color for this line */
+ dstptr = linebuf + slot; /* restart shortly after beginning */
+ if (slot == 3) /* all colors done */
+ {
+ slot = 0; /* back to first color */
+ dstptr = linebuf; /* back to beginning of line */
+ line++; /* number of line just completed */
+ /* use scanner->width instead of width to remove pad bytes */
+ if (line > (chndl->y1) * chndl->val[opt_resolution].w / 600)
+ {
+ if (chndl->params.format == SANE_FRAME_RGB)
+ {
+ memcpy (data + offset, linebuf, 3 * chndl->width);
+ offset += 3 * chndl->width;
+ }
+ else
+ {
+ int grayvalue;
+ int lineelement = 0;
+ while (lineelement < chndl->width)
+ {
+ grayvalue = linebuf[3 * lineelement] +
+ linebuf[3 * lineelement + 1] +
+ linebuf[3 * lineelement + 2];
+ grayvalue /= 3;
+ if (chndl->params.depth == 8) /* gray */
+ {
+ data[offset + lineelement] = (byte) grayvalue;
+ }
+ else /* lineart */
+ {
+ if (lineelement % 8 == 0)
+ {
+ data[offset + (lineelement >> 3)] = 0;
+ }
+ if ((byte) grayvalue <
+ chndl->absolute_threshold)
+ {
+ data[offset + (lineelement >> 3)] |=
+ (1 << (7 - lineelement % 8));
+ }
+ }
+ lineelement++;
+ }
+ offset += chndl->params.bytes_per_line;
+ }
+ DBG (6, "line %ld written...\n", line);
+ }
+
+ if (line == (chndl->y1) * chndl->val[opt_resolution].w / 600
+ + chndl->params.lines)
+ {
+ break;
+ }
+
+ }
+ }
+ } /* one readbuf processed */
+ bytes_written = fwrite (data, 1, offset, fp);
+ DBG (6, "%ld bytes written\n", bytes_written);
+ if (bytes_written != offset)
+ {
+ status = SANE_STATUS_IO_ERROR;
+ }
+ DBG (6, "%ld lines from readbuf\n", line - startline);
+ return status; /* to escape from this loop
+ after processing only one data buffer */
+}
+
+/* Scan and save the resulting image as r,g,b non-interleaved PPM file */
+static SANE_Status
+do_scan (CANON_Handle * chndl)
+{
+ SANE_Status status = SANE_STATUS_GOOD;
+ SANE_Byte outbuf[0x40000];
+ FILE *fp;
+ fp = fopen (chndl->fname, "w");
+ if (!fp)
+ {
+ DBG (1, "err:%s when opening %s\n", strerror (errno), chndl->fname);
+ return SANE_STATUS_IO_ERROR;
+ }
+ int fd = chndl->fd;
+ long width = chndl->params.pixels_per_line;
+ if (chndl->val[opt_resolution].w < 600)
+ {
+ width = width * 600 / chndl->val[opt_resolution].w;
+ }
+ /* set width to next multiple of 0x10 */
+ while ((width % 0x10) != 0xf)
+ {
+ width++;
+ }
+
+ long x_start;
+ long x_end;
+ long left_edge = 0x69;
+ switch (chndl->val[opt_resolution].w)
+ {
+ case 75:
+ case 150:
+ case 300:
+ case 600:
+ left_edge = 0x69;
+ break;
+ case 1200:
+ left_edge = 0x87;
+ }
+ x_start = left_edge + chndl->x1 * chndl->val[opt_resolution].w / 600;
+ if (chndl->val[opt_resolution].w < 600)
+ {
+ x_start = left_edge + chndl->x1;
+ }
+ x_end = x_start + (width);
+ width++;
+
+ chndl->value_08 = (x_start >> 8) & 0xff;
+ chndl->value_09 = (x_start) & 0xff;
+ chndl->value_0a = (x_end >> 8) & 0xff;
+ chndl->value_0b = (x_end) & 0xff;
+
+ DBG (3, "val_08: %02x\n", chndl->value_08);
+ DBG (3, "val_09: %02x\n", chndl->value_09);
+ DBG (3, "val_0a: %02x\n", chndl->value_0a);
+ DBG (3, "val_0b: %02x\n", chndl->value_0b);
+ DBG (3, "chndl->width: %04lx\n", chndl->width);
+
+ send_start_blob (chndl);
+
+ while (status == SANE_STATUS_GOOD)
+ {
+ status = preread (chndl, outbuf, fp);
+ }
+ go_home_without_wait (fd);
+
+ if (status == SANE_STATUS_EOF)
+ {
+ status = SANE_STATUS_GOOD;
+ }
+
+ fclose (fp);
+ DBG (6, "created scan file %s\n", chndl->fname);
+
+ return status;
+}
+
+/* Scan sequence */
+/* resolution is 75,150,300,600,1200
+ scan coordinates in 600-dpi pixels */
+
+static SANE_Status
+scan (CANON_Handle * chndl)
+{
+ SANE_Status status = SANE_STATUS_GOOD;
+ /* Resolution: dpi 75, 150, 300, 600, 1200 */
+ switch (chndl->val[opt_resolution].w)
+ {
+ case 75:
+ case 150:
+ case 300:
+ case 600:
+ case 1200:
+ break;
+ default:
+ chndl->val[opt_resolution].w = 600;
+ }
+
+ chndl->width = chndl->params.pixels_per_line;
+ chndl->height =
+ (chndl->y2 - chndl->y1) * chndl->val[opt_resolution].w / 600;
+ DBG (1, "dpi=%d\n", chndl->val[opt_resolution].w);
+ DBG (1, "x1=%d y1=%d\n", chndl->x1, chndl->y1);
+ DBG (1, "x2=%d y2=%d\n", chndl->x2, chndl->y2);
+ DBG (1, "width=%ld height=%ld\n", chndl->width, chndl->height);
+
+ CHK (do_scan (chndl));
+ return status;
+}
+
+
+static SANE_Status
+CANON_set_scan_parameters (CANON_Handle * chndl)
+{
+ int left;
+ int top;
+ int right;
+ int bottom;
+
+ double leftf;
+ double rightf;
+ double topf;
+ double bottomf;
+
+ double widthf;
+ double heightf;
+ int widthi;
+ int heighti;
+
+ int top_edge = 7;
+ if (chndl->val[opt_resolution].w < 300)
+ {
+ top_edge = 0;
+ }
+
+ left = SANE_UNFIX (chndl->val[opt_tl_x].w) / MM_IN_INCH * 600;
+ top = (top_edge + SANE_UNFIX (chndl->val[opt_tl_y].w)) / MM_IN_INCH * 600;
+ right = SANE_UNFIX (chndl->val[opt_br_x].w) / MM_IN_INCH * 600;
+ bottom =
+ (top_edge + SANE_UNFIX (chndl->val[opt_br_y].w)) / MM_IN_INCH * 600;
+
+ leftf = SANE_UNFIX (chndl->val[opt_tl_x].w);
+ rightf = SANE_UNFIX (chndl->val[opt_br_x].w);
+ topf = SANE_UNFIX (chndl->val[opt_tl_y].w);
+ bottomf = SANE_UNFIX (chndl->val[opt_br_y].w);
+
+ widthf = (rightf - leftf) / MM_PER_INCH * 600;
+ widthi = (int) widthf;
+ heightf = (bottomf - topf) / MM_PER_INCH * 600;
+ heighti = (int) heightf;
+
+ DBG (2, "CANON_set_scan_parameters:\n");
+ DBG (2, "widthf = %f\n", widthf);
+ DBG (2, "widthi = %d\n", widthi);
+ DBG (2, "in 600dpi pixels:\n");
+ DBG (2, "left = %d, top = %d\n", left, top);
+ DBG (2, "right = %d, bottom = %d\n", right, bottom);
+
+ /* Validate the input parameters */
+ if ((left < 0) || (right > CANON_MAX_WIDTH))
+ {
+ return SANE_STATUS_INVAL;
+ }
+
+ if ((top < 0) || (bottom > CANON_MAX_HEIGHT))
+ {
+ return SANE_STATUS_INVAL;
+ }
+
+ if (((right - left) < 10) || ((bottom - top) < 10))
+ {
+ return SANE_STATUS_INVAL;
+ }
+
+ if ((chndl->val[opt_resolution].w != 75) &&
+ (chndl->val[opt_resolution].w != 150) &&
+ (chndl->val[opt_resolution].w != 300) &&
+ (chndl->val[opt_resolution].w != 600) &&
+ (chndl->val[opt_resolution].w != 1200))
+ {
+ return SANE_STATUS_INVAL;
+ }
+
+ /* Store params */
+ chndl->x1 = left;
+ chndl->x2 = left + widthi;
+ chndl->y1 = top;
+ chndl->y2 = top + heighti;
+ chndl->absolute_threshold = (chndl->val[opt_threshold].w * 255) / 100;
+ return SANE_STATUS_GOOD;
+}
+
+
+static SANE_Status
+CANON_close_device (CANON_Handle * scan)
+{
+ DBG (3, "CANON_close_device:\n");
+ sanei_usb_close (scan->fd);
+ return SANE_STATUS_GOOD;
+}
+
+
+static SANE_Status
+CANON_open_device (CANON_Handle * scan, const char *dev)
+{
+ SANE_Word vendor;
+ SANE_Word product;
+ SANE_Status res;
+
+ DBG (3, "CANON_open_device: `%s'\n", dev);
+
+ scan->fname = NULL;
+ scan->fp = NULL;
+
+ res = sanei_usb_open (dev, &scan->fd);
+
+ if (res != SANE_STATUS_GOOD)
+ {
+ DBG (1, "CANON_open_device: couldn't open device `%s': %s\n", dev,
+ sane_strstatus (res));
+ return res;
+ }
+
+ scan->product = "unknown";
+
+#ifndef NO_AUTODETECT
+ /* We have opened the device. Check that it is a USB scanner. */
+ if (sanei_usb_get_vendor_product (scan->fd, &vendor, &product) !=
+ SANE_STATUS_GOOD)
+ {
+ DBG (1, "CANON_open_device: sanei_usb_get_vendor_product failed\n");
+ /* This is not a USB scanner, or SANE or the OS doesn't support it. */
+ sanei_usb_close (scan->fd);
+ scan->fd = -1;
+ return SANE_STATUS_UNSUPPORTED;
+ }
+
+ /* Make sure we have a CANON scanner */
+ if (vendor == 0x04a9)
+ {
+ scan->product = "Canon";
+
+ if (product == 0x2224)
+ {
+ scan->product = "CanoScan LiDE 600F";
+ }
+ else if (product == 0x2225)
+ {
+ scan->product = "CanoScan LiDE 70";
+ }
+ else
+ {
+ DBG (1, "CANON_open_device: incorrect vendor/product (0x%x/0x%x)\n",
+ vendor, product);
+ sanei_usb_close (scan->fd);
+ scan->fd = -1;
+ return SANE_STATUS_UNSUPPORTED;
+ }
+ }
+#endif
+
+ return SANE_STATUS_GOOD;
+}
+
+
+static const char *
+CANON_get_device_name (CANON_Handle * chndl)
+{
+ return chndl->product;
+}
+
+
+static SANE_Status
+CANON_finish_scan (CANON_Handle * chndl)
+{
+ DBG (3, "CANON_finish_scan:\n");
+
+ if (chndl->fp)
+ {
+ fclose (chndl->fp);
+ }
+
+ chndl->fp = NULL;
+
+ /* remove temp file */
+ if (chndl->fname)
+ {
+ DBG (4, "removing temp file %s\n", chndl->fname);
+ unlink (chndl->fname);
+ free (chndl->fname);
+ }
+
+ chndl->fname = NULL;
+ return SANE_STATUS_GOOD;
+}
+
+
+static SANE_Status
+CANON_start_scan (CANON_Handle * chndl)
+{
+ SANE_Status status;
+ int result;
+ int fd;
+ DBG (3, "CANON_start_scan called\n");
+
+ /* choose a temp file name for scan data */
+ chndl->fname = strdup ("/tmp/scan.XXXXXX");
+ fd = mkstemp (chndl->fname);
+
+ if (!fd)
+ {
+ return SANE_STATUS_IO_ERROR;
+ }
+
+ close (fd);
+
+ /* check if calibration needed */
+ result = init (chndl);
+
+ if (result < 0)
+ {
+ DBG (1, "Can't talk on USB.\n");
+ return SANE_STATUS_IO_ERROR;
+ }
+
+ go_home (chndl->fd);
+
+ /* scan */
+ if ((status = scan (chndl)) != SANE_STATUS_GOOD)
+ {
+ CANON_finish_scan (chndl);
+ return status;
+ }
+
+ /* read the temp file back out */
+ chndl->fp = fopen (chndl->fname, "r");
+ DBG (4, "reading %s\n", chndl->fname);
+
+ if (!chndl->fp)
+ {
+ DBG (1, "open %s", chndl->fname);
+ return SANE_STATUS_IO_ERROR;
+ }
+
+ return SANE_STATUS_GOOD;
+}
+
+
+static SANE_Status
+CANON_read (CANON_Handle * chndl, SANE_Byte * data,
+ SANE_Int max_length, SANE_Int * length)
+{
+ SANE_Status status;
+ int read_len;
+
+ DBG (5, "CANON_read called\n");
+
+ if (!chndl->fp)
+ {
+ return SANE_STATUS_INVAL;
+ }
+
+ read_len = fread (data, 1, max_length, chndl->fp);
+ /* return some data */
+ if (read_len > 0)
+ {
+ *length = read_len;
+ DBG (5, "CANON_read returned (%d/%d)\n", *length, max_length);
+ return SANE_STATUS_GOOD;
+ }
+
+ /* EOF or file err */
+ *length = 0;
+
+ if (feof (chndl->fp))
+ {
+ DBG (4, "EOF\n");
+ status = SANE_STATUS_EOF;
+ }
+ else
+ {
+ DBG (4, "IO ERR\n");
+ status = SANE_STATUS_IO_ERROR;
+ }
+
+ CANON_finish_scan (chndl);
+ DBG (5, "CANON_read returned (%d/%d)\n", *length, max_length);
+ return status;
+}
diff --git a/backend/canon_lide70.c b/backend/canon_lide70.c
new file mode 100644
index 0000000..100a45f
--- /dev/null
+++ b/backend/canon_lide70.c
@@ -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;
+}
diff --git a/backend/canon_lide70.conf.in b/backend/canon_lide70.conf.in
new file mode 100644
index 0000000..97b551c
--- /dev/null
+++ b/backend/canon_lide70.conf.in
@@ -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
diff --git a/backend/dll.c b/backend/dll.c
index 73ffde4..d78d409 100644
--- a/backend/dll.c
+++ b/backend/dll.c
@@ -142,6 +142,10 @@ posix_dlsym (void *handle, const char *func)
# define PATH_MAX 1024
#endif
+#ifndef NAME_MAX
+# define NAME_MAX FILENAME_MAX
+#endif
+
#if defined(_WIN32) || defined(HAVE_OS2_H)
# define DIR_SEP ";"
#else
diff --git a/backend/dll.conf.in b/backend/dll.conf.in
index 92091cb..cc7dfec 100644
--- a/backend/dll.conf.in
+++ b/backend/dll.conf.in
@@ -19,6 +19,7 @@ bh
canon
canon630u
canon_dr
+canon_lide70
#canon_pp
cardscan
coolscan
diff --git a/backend/dmc.c b/backend/dmc.c
index ddc76c3..363a33f 100644
--- a/backend/dmc.c
+++ b/backend/dmc.c
@@ -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;
diff --git a/backend/epsonds-net.c b/backend/epsonds-net.c
index 8ea236b..3c8be29 100644
--- a/backend/epsonds-net.c
+++ b/backend/epsonds-net.c
@@ -32,11 +32,12 @@
#include "sane/sanei_debug.h"
-static int
+static ssize_t
epsonds_net_read_raw(epsonds_scanner *s, unsigned char *buf, ssize_t wanted,
SANE_Status *status)
{
- int ready, read = -1;
+ int ready;
+ ssize_t read = -1;
fd_set readable;
struct timeval tv;
@@ -62,106 +63,98 @@ epsonds_net_read_raw(epsonds_scanner *s, unsigned char *buf, ssize_t wanted,
return read;
}
-int
-epsonds_net_read(epsonds_scanner *s, unsigned char *buf, ssize_t wanted,
+static ssize_t
+epsonds_net_read_buf(epsonds_scanner *s, unsigned char *buf, ssize_t wanted,
SANE_Status * status)
{
- ssize_t size;
ssize_t read = 0;
- unsigned char header[12];
- /* read from buffer, if available */
- if (wanted && s->netptr != s->netbuf) {
- DBG(23, "reading %lu from buffer at %p, %lu available\n",
- (u_long) wanted, s->netptr, (u_long) s->netlen);
+ DBG(23, "%s: reading up to %lu from buffer at %p, %lu available\n",
+ __func__, (u_long) wanted, s->netptr, (u_long) s->netlen);
- memcpy(buf, s->netptr, wanted);
- read = wanted;
+ if ((size_t) wanted > s->netlen) {
+ *status = SANE_STATUS_IO_ERROR;
+ wanted = s->netlen;
+ }
- s->netlen -= wanted;
+ memcpy(buf, s->netptr, wanted);
+ read = wanted;
- if (s->netlen == 0) {
- DBG(23, "%s: freeing %p\n", __func__, s->netbuf);
- free(s->netbuf);
- s->netbuf = s->netptr = NULL;
- s->netlen = 0;
- }
+ s->netptr += read;
+ s->netlen -= read;
+
+ if (s->netlen == 0) {
+ DBG(23, "%s: freeing %p\n", __func__, s->netbuf);
+ free(s->netbuf);
+ s->netbuf = s->netptr = NULL;
+ s->netlen = 0;
+ }
+
+ return read;
+}
+
+ssize_t
+epsonds_net_read(epsonds_scanner *s, unsigned char *buf, ssize_t wanted,
+ SANE_Status * status)
+{
+ if (wanted < 0) {
+ *status = SANE_STATUS_INVAL;
+ return 0;
+ }
- return read;
+ size_t size;
+ ssize_t read = 0;
+ unsigned char header[12];
+
+ /* read from remainder of buffer */
+ if (s->netptr) {
+ return epsonds_net_read_buf(s, buf, wanted, status);
}
/* receive net header */
- size = epsonds_net_read_raw(s, header, 12, status);
- if (size != 12) {
+ read = epsonds_net_read_raw(s, header, 12, status);
+ if (read != 12) {
return 0;
}
+ /* validate header */
if (header[0] != 'I' || header[1] != 'S') {
DBG(1, "header mismatch: %02X %02x\n", header[0], header[1]);
*status = SANE_STATUS_IO_ERROR;
return 0;
}
- // incoming payload size
+ /* parse payload size */
size = be32atoh(&header[6]);
- DBG(23, "%s: wanted = %lu, available = %lu\n", __func__,
- (u_long) wanted, (u_long) size);
-
*status = SANE_STATUS_GOOD;
- if (size == wanted) {
+ if (!s->netbuf) {
+ DBG(15, "%s: direct read\n", __func__);
+ DBG(23, "%s: wanted = %lu, available = %lu\n", __func__,
+ (u_long) wanted, (u_long) size);
- DBG(15, "%s: full read\n", __func__);
-
- if (size) {
- read = epsonds_net_read_raw(s, buf, size, status);
+ if ((size_t) wanted > size) {
+ wanted = size;
}
- if (s->netbuf) {
- free(s->netbuf);
- s->netbuf = NULL;
- s->netlen = 0;
- }
-
- if (read < 0) {
- return 0;
- }
-
- } else if (wanted < size) {
-
- DBG(23, "%s: long tail\n", __func__);
-
- read = epsonds_net_read_raw(s, s->netbuf, size, status);
- if (read != size) {
- return 0;
- }
-
- memcpy(buf, s->netbuf, wanted);
- read = wanted;
-
- free(s->netbuf);
- s->netbuf = NULL;
- s->netlen = 0;
-
+ read = epsonds_net_read_raw(s, buf, wanted, status);
} else {
+ DBG(15, "%s: buffered read\n", __func__);
+ DBG(23, "%s: bufferable = %lu, available = %lu\n", __func__,
+ (u_long) s->netlen, (u_long) size);
- DBG(23, "%s: partial read\n", __func__);
-
- read = epsonds_net_read_raw(s, s->netbuf, size, status);
- if (read != size) {
- return 0;
+ if (s->netlen > size) {
+ s->netlen = size;
}
- s->netlen = size - wanted;
- s->netptr += wanted;
- read = wanted;
-
- DBG(23, "0,4 %02x %02x\n", s->netbuf[0], s->netbuf[4]);
- DBG(23, "storing %lu to buffer at %p, next read at %p, %lu bytes left\n",
- (u_long) size, s->netbuf, s->netptr, (u_long) s->netlen);
+ /* fill buffer */
+ read = epsonds_net_read_raw(s, s->netbuf, s->netlen, status);
+ s->netptr = s->netbuf;
+ s->netlen = (read > 0 ? read : 0);
- memcpy(buf, s->netbuf, wanted);
+ /* copy wanted part */
+ read = epsonds_net_read_buf(s, buf, wanted, status);
}
return read;
@@ -175,23 +168,38 @@ epsonds_net_request_read(epsonds_scanner *s, size_t len)
return status;
}
-int
+size_t
epsonds_net_write(epsonds_scanner *s, unsigned int cmd, const unsigned char *buf,
size_t buf_size, size_t reply_len, SANE_Status *status)
{
unsigned char *h1, *h2;
unsigned char *packet = malloc(12 + 8);
- /* XXX check allocation failure */
+ if (!packet) {
+ *status = SANE_STATUS_NO_MEM;
+ return 0;
+ }
h1 = packet; // packet header
h2 = packet + 12; // data header
if (reply_len) {
- s->netbuf = s->netptr = malloc(reply_len);
+ if (s->netbuf) {
+ DBG(23, "%s, freeing %p, %ld bytes unprocessed\n",
+ __func__, s->netbuf, (u_long) s->netlen);
+ free(s->netbuf);
+ s->netbuf = s->netptr = NULL;
+ s->netlen = 0;
+ }
+ s->netbuf = malloc(reply_len);
+ if (!s->netbuf) {
+ free(packet);
+ *status = SANE_STATUS_NO_MEM;
+ return 0;
+ }
s->netlen = reply_len;
- DBG(24, "allocated %lu bytes at %p\n",
- (u_long) reply_len, s->netbuf);
+ DBG(24, "%s: allocated %lu bytes at %p\n", __func__,
+ (u_long) s->netlen, s->netbuf);
}
DBG(24, "%s: cmd = %04x, buf = %p, buf_size = %lu, reply_len = %lu\n",
diff --git a/backend/epsonds-net.h b/backend/epsonds-net.h
index f7b173e..107301b 100644
--- a/backend/epsonds-net.h
+++ b/backend/epsonds-net.h
@@ -4,9 +4,9 @@
#include <sys/types.h>
#include "../include/sane/sane.h"
-extern int epsonds_net_read(struct epsonds_scanner *s, unsigned char *buf, ssize_t buf_size,
+extern ssize_t epsonds_net_read(struct epsonds_scanner *s, unsigned char *buf, ssize_t buf_size,
SANE_Status *status);
-extern int epsonds_net_write(struct epsonds_scanner *s, unsigned int cmd, const unsigned char *buf,
+extern size_t epsonds_net_write(struct epsonds_scanner *s, unsigned int cmd, const unsigned char *buf,
size_t buf_size, size_t reply_len,
SANE_Status *status);
extern SANE_Status epsonds_net_lock(struct epsonds_scanner *s);
diff --git a/backend/epsonds.c b/backend/epsonds.c
index fb9694a..f2af220 100644
--- a/backend/epsonds.c
+++ b/backend/epsonds.c
@@ -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"
@@ -245,8 +247,8 @@ open_scanner(epsonds_scanner *s)
/* the scanner sends a kind of welcome msg */
// XXX check command type, answer to connect is 0x80
- read = eds_recv(s, buf, 3, &status);
- if (read != 3) {
+ read = eds_recv(s, buf, 5, &status);
+ if (read != 5) {
sanei_tcp_close(s->fd);
s->fd = -1;
return SANE_STATUS_IO_ERROR;
diff --git a/backend/escl.conf.in b/backend/escl.conf.in
index 2aa6257..9c482b5 100644
--- a/backend/escl.conf.in
+++ b/backend/escl.conf.in
@@ -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]
diff --git a/backend/escl/escl.c b/backend/escl/escl.c
index 8df6c5c..c40fd98 100644
--- a/backend/escl/escl.c
+++ b/backend/escl/escl.c
@@ -46,14 +46,16 @@ static int num_devices = 0;
typedef struct Handled {
struct Handled *next;
- SANE_String_Const name;
+ ESCL_Device *device;
char *result;
ESCL_ScanParam param;
SANE_Option_Descriptor opt[NUM_OPTIONS];
Option_Value val[NUM_OPTIONS];
capabilities_t *scanner;
- SANE_Range x_range;
- SANE_Range y_range;
+ SANE_Range x_range1;
+ SANE_Range x_range2;
+ SANE_Range y_range1;
+ SANE_Range y_range2;
SANE_Bool cancel;
SANE_Bool write_scan_data;
SANE_Bool decompress_scan_data;
@@ -61,6 +63,59 @@ typedef struct Handled {
SANE_Parameters ps;
} escl_sane_t;
+static ESCL_Device *
+escl_free_device(ESCL_Device *current)
+{
+ if (!current) return NULL;
+ free((void*)current->ip_address);
+ free((void*)current->model_name);
+ free((void*)current->type);
+ free(current->unix_socket);
+ free(current);
+ return NULL;
+}
+
+void
+escl_free_handler(escl_sane_t *handler)
+{
+ if (handler == NULL)
+ return;
+
+ escl_free_device(handler->device);
+ free(handler);
+}
+
+SANE_Status escl_parse_name(SANE_String_Const name, ESCL_Device *device);
+
+static SANE_Status
+escl_check_and_add_device(ESCL_Device *current)
+{
+ if(!current) {
+ DBG (10, "ESCL_Device *current us null.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+ if (!current->ip_address) {
+ DBG (10, "Ip Address allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+ if (current->port_nb == 0) {
+ DBG (10, "No port defined.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+ if (!current->model_name) {
+ DBG (10, "Modele Name allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+ if (!current->type) {
+ DBG (10, "Scanner Type allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+ ++num_devices;
+ current->next = list_devices_primary;
+ list_devices_primary = current;
+ return (SANE_STATUS_GOOD);
+}
+
/**
* \fn static SANE_Status escl_add_in_list(ESCL_Device *current)
* \brief Function that adds all the element needed to my list :
@@ -72,10 +127,18 @@ typedef struct Handled {
static SANE_Status
escl_add_in_list(ESCL_Device *current)
{
- ++num_devices;
- current->next = list_devices_primary;
- list_devices_primary = current;
- return (SANE_STATUS_GOOD);
+ if(!current) {
+ DBG (10, "ESCL_Device *current us null.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+
+ if (SANE_STATUS_GOOD ==
+ escl_check_and_add_device(current)) {
+ list_devices_primary = current;
+ return (SANE_STATUS_GOOD);
+ }
+ current = escl_free_device(current);
+ return (SANE_STATUS_NO_MEM);
}
/**
@@ -89,19 +152,44 @@ escl_add_in_list(ESCL_Device *current)
SANE_Status
escl_device_add(int port_nb, const char *model_name, char *ip_address, char *type)
{
+ char tmp[PATH_MAX] = { 0 };
+ char *model = NULL;
ESCL_Device *current = NULL;
DBG (10, "escl_device_add\n");
for (current = list_devices_primary; current; current = current->next) {
- if (strcmp(current->ip_address, ip_address) == 0 && current->port_nb == port_nb
- && strcmp(current->type, type) == 0)
- return (SANE_STATUS_GOOD);
+ if (strcmp(current->ip_address, ip_address) == 0)
+ {
+ if (strcmp(current->type, type))
+ {
+ if(!strcmp(type, "_uscans._tcp") ||
+ !strcmp(type, "https"))
+ {
+ free (current->type);
+ current->type = strdup(type);
+ current->port_nb = port_nb;
+ current->https = SANE_TRUE;
+ }
+ return (SANE_STATUS_GOOD);
+ }
+ else if (current->port_nb == port_nb)
+ return (SANE_STATUS_GOOD);
+ }
+ }
+ current = (ESCL_Device*)calloc(1, sizeof(*current));
+ if (current == NULL) {
+ DBG (10, "New device allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
}
- current = malloc(sizeof(*current));
- if (current == NULL)
- return (SANE_STATUS_NO_MEM);
- memset(current, 0, sizeof(*current));
current->port_nb = port_nb;
- current->model_name = strdup(model_name);
+
+ if (strcmp(type, "_uscan._tcp") != 0 && strcmp(type, "http") != 0) {
+ snprintf(tmp, sizeof(tmp), "%s SSL", model_name);
+ current->https = SANE_TRUE;
+ } else {
+ current->https = SANE_FALSE;
+ }
+ model = (char*)(tmp[0] != 0 ? tmp : model_name);
+ current->model_name = strdup(model);
current->ip_address = strdup(ip_address);
current->type = strdup(type);
return escl_add_in_list(current);
@@ -121,13 +209,51 @@ max_string_size(const SANE_String_Const strings[])
int i = 0;
for (i = 0; strings[i]; ++i) {
- size_t size = strlen (strings[i]);
- if (size > max_size)
- max_size = size;
+ size_t size = strlen (strings[i]);
+ if (size > max_size)
+ max_size = size;
}
return (max_size + 1);
}
+static char *
+get_vendor(char *search)
+{
+ if(strcasestr(search, "Epson"))
+ return strdup("Epson");
+ else if(strcasestr(search, "Fujitsu"))
+ return strdup("Fujitsu");
+ else if(strcasestr(search, "HP"))
+ return strdup("HP");
+ else if(strcasestr(search, "Canon"))
+ return strdup("Canon");
+ else if(strcasestr(search, "Lexmark"))
+ return strdup("Lexmark");
+ else if(strcasestr(search, "Samsung"))
+ return strdup("Samsung");
+ else if(strcasestr(search, "Xerox"))
+ return strdup("Xerox");
+ else if(strcasestr(search, "OKI"))
+ return strdup("OKI");
+ else if(strcasestr(search, "Hewlett Packard"))
+ return strdup("Hewlett Packard");
+ else if(strcasestr(search, "IBM"))
+ return strdup("IBM");
+ else if(strcasestr(search, "Mustek"))
+ return strdup("Mustek");
+ else if(strcasestr(search, "Ricoh"))
+ return strdup("Ricoh");
+ else if(strcasestr(search, "Sharp"))
+ return strdup("Sharp");
+ else if(strcasestr(search, "UMAX"))
+ return strdup("UMAX");
+ else if(strcasestr(search, "PINT"))
+ return strdup("PINT");
+ else if(strcasestr(search, "Brother"))
+ return strdup("Brother");
+ return NULL;
+}
+
/**
* \fn static SANE_Device *convertFromESCLDev(ESCL_Device *cdev)
* \brief Function that checks if the url of the received scanner is secured or not (http / https).
@@ -142,19 +268,61 @@ max_string_size(const SANE_String_Const strings[])
static SANE_Device *
convertFromESCLDev(ESCL_Device *cdev)
{
+ char *tmp;
+ int len, lv = 0;
+ char unix_path[PATH_MAX+7] = { 0 };
SANE_Device *sdev = (SANE_Device*) calloc(1, sizeof(SANE_Device));
- char tmp[PATH_MAX] = { 0 };
+ if (!sdev) {
+ DBG (10, "Sane_Device allocation failure.\n");
+ return NULL;
+ }
+
+ if (cdev->unix_socket && strlen(cdev->unix_socket)) {
+ snprintf(unix_path, sizeof(unix_path), "unix:%s:", cdev->unix_socket);
+ }
+ len = snprintf(NULL, 0, "%shttp%s://%s:%d",
+ unix_path, cdev->https ? "s" : "", cdev->ip_address, cdev->port_nb);
+ len++;
+ tmp = (char *)malloc(len);
+ if (!tmp) {
+ DBG (10, "Name allocation failure.\n");
+ goto freedev;
+ }
+ snprintf(tmp, len, "%shttp%s://%s:%d",
+ unix_path, cdev->https ? "s" : "", cdev->ip_address, cdev->port_nb);
+ sdev->name = tmp;
- if (strcmp(cdev->type, "_uscan._tcp") == 0 || strcmp(cdev->type, "http") == 0)
- snprintf(tmp, sizeof(tmp), "http://%s:%d", cdev->ip_address, cdev->port_nb);
- else
- snprintf(tmp, sizeof(tmp), "https://%s:%d", cdev->ip_address, cdev->port_nb);
DBG( 1, "Escl add device : %s\n", tmp);
- sdev->name = strdup(tmp);
- sdev->model = strdup(cdev->model_name);
- sdev->vendor = strdup("ESCL");
+ sdev->vendor = get_vendor(cdev->model_name);
+
+ if (!sdev->vendor)
+ sdev->vendor = strdup("ESCL");
+ else
+ lv = strlen(sdev->vendor) + 1;
+ if (!sdev->vendor) {
+ DBG (10, "Vendor allocation failure.\n");
+ goto freemodel;
+ }
+ sdev->model = strdup(lv + cdev->model_name);
+ if (!sdev->model) {
+ DBG (10, "Model allocation failure.\n");
+ goto freename;
+ }
sdev->type = strdup("flatbed scanner");
+ if (!sdev->type) {
+ DBG (10, "Scanner Type allocation failure.\n");
+ goto freevendor;
+ }
return (sdev);
+freevendor:
+ free((void*)sdev->vendor);
+freemodel:
+ free((void*)sdev->model);
+freename:
+ free((void*)sdev->name);
+freedev:
+ free((void*)sdev);
+ return NULL;
}
/**
@@ -174,9 +342,9 @@ sane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize)
SANE_Status status = SANE_STATUS_GOOD;
curl_global_init(CURL_GLOBAL_ALL);
if (version_code != NULL)
- *version_code = SANE_VERSION_CODE(1, 0, 0);
+ *version_code = SANE_VERSION_CODE(1, 0, 0);
if (status != SANE_STATUS_GOOD)
- return (status);
+ return (status);
return (SANE_STATUS_GOOD);
}
@@ -194,12 +362,12 @@ sane_exit(void)
ESCL_Device *next = NULL;
while (list_devices_primary != NULL) {
- next = list_devices_primary->next;
- free(list_devices_primary);
- list_devices_primary = next;
+ next = list_devices_primary->next;
+ free(list_devices_primary);
+ list_devices_primary = next;
}
if (devlist)
- free (devlist);
+ free (devlist);
list_devices_primary = NULL;
devlist = NULL;
curl_global_cleanup();
@@ -218,44 +386,85 @@ static SANE_Status
attach_one_config(SANEI_Config __sane_unused__ *config, const char *line)
{
int port = 0;
- static int count = 0;
+ SANE_Status status;
static ESCL_Device *escl_device = NULL;
- if (strncmp(line, "[device]", 8) == 0) {
- count = 0;
+ if (strncmp(line, "device", 6) == 0) {
+ char *name_str = NULL;
+ char *opt_model = NULL;
+
+ line = sanei_config_get_string(line + 6, &name_str);
+ DBG (10, "New Escl_Device URL [%s].\n", (name_str ? name_str : "VIDE"));
+ if (!name_str || !*name_str) {
+ DBG (1, "Escl_Device URL missing.\n");
+ return SANE_STATUS_INVAL;
+ }
+ if (*line) {
+ line = sanei_config_get_string(line, &opt_model);
+ DBG (10, "New Escl_Device model [%s].\n", opt_model);
+ }
+
+ escl_free_device(escl_device);
escl_device = (ESCL_Device*)calloc(1, sizeof(ESCL_Device));
+ if (!escl_device) {
+ DBG (10, "New Escl_Device allocation failure.\n");
+ free(name_str);
+ return (SANE_STATUS_NO_MEM);
+ }
+ status = escl_parse_name(name_str, escl_device);
+ free(name_str);
+ if (status != SANE_STATUS_GOOD) {
+ escl_free_device(escl_device);
+ escl_device = NULL;
+ return status;
+ }
+ escl_device->model_name = opt_model ? opt_model : strdup("Unknown model");
+ escl_device->type = strdup("flatbed scanner");
+ }
+
+ if (strncmp(line, "[device]", 8) == 0) {
+ escl_device = escl_free_device(escl_device);
+ escl_device = (ESCL_Device*)calloc(1, sizeof(ESCL_Device));
+ if (!escl_device) {
+ DBG (10, "New Escl_Device allocation failure.");
+ return (SANE_STATUS_NO_MEM);
+ }
}
if (strncmp(line, "ip", 2) == 0) {
- const char *ip_space = sanei_config_skip_whitespace(line + 2);
- if (escl_device != NULL && ip_space != NULL) {
- count++;
- escl_device->ip_address = strdup(ip_space);
- }
+ const char *ip_space = sanei_config_skip_whitespace(line + 2);
+ DBG (10, "New Escl_Device IP [%s].", (ip_space ? ip_space : "VIDE"));
+ if (escl_device != NULL && ip_space != NULL) {
+ DBG (10, "New Escl_Device IP Affected.");
+ escl_device->ip_address = strdup(ip_space);
+ }
}
if (sscanf(line, "port %i", &port) == 1 && port != 0) {
- const char *port_space = sanei_config_skip_whitespace(line + 4);
- if (escl_device != NULL && port_space != NULL) {
- count++;
- escl_device->port_nb = port;
- }
+ DBG (10, "New Escl_Device PORT [%d].", port);
+ if (escl_device != NULL) {
+ DBG (10, "New Escl_Device PORT Affected.");
+ escl_device->port_nb = port;
+ }
}
if (strncmp(line, "model", 5) == 0) {
- const char *model_space = sanei_config_skip_whitespace(line + 5);
- if (escl_device != NULL && model_space != NULL) {
- count++;
- escl_device->model_name = strdup(model_space);
- }
+ const char *model_space = sanei_config_skip_whitespace(line + 5);
+ DBG (10, "New Escl_Device MODEL [%s].", (model_space ? model_space : "VIDE"));
+ if (escl_device != NULL && model_space != NULL) {
+ DBG (10, "New Escl_Device MODEL Affected.");
+ escl_device->model_name = strdup(model_space);
+ }
}
if (strncmp(line, "type", 4) == 0) {
- const char *type_space = sanei_config_skip_whitespace(line + 4);
- if (escl_device != NULL && type_space != NULL) {
- count++;
- escl_device->type = strdup(type_space);
- }
+ const char *type_space = sanei_config_skip_whitespace(line + 4);
+ DBG (10, "New Escl_Device TYPE [%s].", (type_space ? type_space : "VIDE"));
+ if (escl_device != NULL && type_space != NULL) {
+ DBG (10, "New Escl_Device TYPE Affected.");
+ escl_device->type = strdup(type_space);
+ }
}
- if (count == 4)
- return (escl_add_in_list(escl_device));
- return (SANE_STATUS_GOOD);
+ status = escl_check_and_add_device(escl_device);
+ if (status == SANE_STATUS_GOOD)
+ escl_device = NULL;
+ return status;
}
/**
@@ -269,7 +478,7 @@ SANE_Status
sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
{
if (local_only) /* eSCL is a network-only protocol */
- return (device_list ? SANE_STATUS_GOOD : SANE_STATUS_INVAL);
+ return (device_list ? SANE_STATUS_GOOD : SANE_STATUS_INVAL);
DBG (10, "escl sane_get_devices\n");
ESCL_Device *dev = NULL;
@@ -277,29 +486,46 @@ sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
SANE_Status status;
if (device_list == NULL)
- return (SANE_STATUS_INVAL);
+ return (SANE_STATUS_INVAL);
status = sanei_configure_attach(ESCL_CONFIG_FILE, NULL, attach_one_config);
if (status != SANE_STATUS_GOOD)
- return (status);
+ return (status);
escl_devices(&status);
if (status != SANE_STATUS_GOOD)
- return (status);
+ return (status);
if (devlist)
- free(devlist);
+ free(devlist);
devlist = (const SANE_Device **) calloc (num_devices + 1, sizeof (devlist[0]));
if (devlist == NULL)
- return (SANE_STATUS_NO_MEM);
+ return (SANE_STATUS_NO_MEM);
int i = 0;
for (dev = list_devices_primary; i < num_devices; dev = dev->next) {
- SANE_Device *s_dev = convertFromESCLDev(dev);
- devlist[i] = s_dev;
- i++;
+ SANE_Device *s_dev = convertFromESCLDev(dev);
+ devlist[i] = s_dev;
+ i++;
}
devlist[i] = 0;
*device_list = devlist;
return (devlist) ? SANE_STATUS_GOOD : SANE_STATUS_NO_MEM;
}
+/* Returns the length of the longest string, including the terminating
+ * character. */
+static size_t
+_source_size_max (SANE_String_Const * sources)
+{
+ size_t size = 0;
+
+ while(*sources)
+ {
+ size_t t = strlen (*sources) + 1;
+ if (t > size)
+ size = t;
+ sources++;
+ }
+ return size;
+}
+
/**
* \fn static SANE_Status init_options(SANE_String_Const name, escl_sane_t *s)
* \brief Function thzt initializes all the needed options of the received scanner
@@ -309,26 +535,51 @@ sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
* \return status (if everything is OK, status = SANE_STATUS_GOOD)
*/
static SANE_Status
-init_options(SANE_String_Const name, escl_sane_t *s)
+init_options(SANE_String_Const name_source, escl_sane_t *s)
{
DBG (10, "escl init_options\n");
+
SANE_Status status = SANE_STATUS_GOOD;
int i = 0;
-
- if (name == NULL)
- return (SANE_STATUS_INVAL);
+ if (!s->scanner) return SANE_STATUS_INVAL;
+ if (name_source) {
+ int source = s->scanner->source;
+ DBG (10, "escl init_options name [%s]\n", name_source);
+ if (!strcmp(name_source, SANE_I18N ("ADF Duplex")))
+ s->scanner->source = ADFDUPLEX;
+ else if (!strncmp(name_source, "A", 1) ||
+ !strcmp(name_source, SANE_I18N ("ADF")))
+ s->scanner->source = ADFSIMPLEX;
+ else
+ s->scanner->source = PLATEN;
+ if (source == s->scanner->source) return status;
+ }
+ else
+ s->scanner->source = PLATEN;
memset (s->opt, 0, sizeof (s->opt));
memset (s->val, 0, sizeof (s->val));
for (i = 0; i < NUM_OPTIONS; ++i) {
- s->opt[i].size = sizeof (SANE_Word);
- s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
- }
- s->x_range.min = 0;
- s->x_range.max = s->scanner->MaxWidth - s->scanner->MinWidth;
- s->x_range.quant = 1;
- s->y_range.min = 0;
- s->y_range.max = s->scanner->MaxHeight - s->scanner->MinHeight;
- s->y_range.quant = 1;
+ s->opt[i].size = sizeof (SANE_Word);
+ s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ }
+ s->x_range1.min = 0;
+ s->x_range1.max =
+ PIXEL_TO_MM((s->scanner->caps[s->scanner->source].MaxWidth -
+ s->scanner->caps[s->scanner->source].MinWidth),
+ 300.0);
+ s->x_range1.quant = 0;
+ s->x_range2.min = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MinWidth, 300.0);
+ s->x_range2.max = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MaxWidth, 300.0);
+ s->x_range2.quant = 0;
+ s->y_range1.min = 0;
+ s->y_range1.max =
+ PIXEL_TO_MM((s->scanner->caps[s->scanner->source].MaxHeight -
+ s->scanner->caps[s->scanner->source].MinHeight),
+ 300.0);
+ s->y_range1.quant = 0;
+ s->y_range2.min = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MinHeight, 300.0);
+ s->y_range2.max = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MaxHeight, 300.0);
+ s->y_range2.quant = 0;
s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
@@ -347,10 +598,18 @@ init_options(SANE_String_Const name, escl_sane_t *s)
s->opt[OPT_MODE].type = SANE_TYPE_STRING;
s->opt[OPT_MODE].unit = SANE_UNIT_NONE;
s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
- s->opt[OPT_MODE].constraint.string_list = s->scanner->ColorModes;
- s->val[OPT_MODE].s = (char *)strdup(s->scanner->ColorModes[0]);
- s->opt[OPT_MODE].size = max_string_size(s->scanner->ColorModes);
- s->scanner->default_color = (char *)strdup(s->scanner->ColorModes[0]);
+ s->opt[OPT_MODE].constraint.string_list = s->scanner->caps[s->scanner->source].ColorModes;
+ s->val[OPT_MODE].s = (char *)strdup(s->scanner->caps[s->scanner->source].ColorModes[0]);
+ if (!s->val[OPT_MODE].s) {
+ DBG (10, "Color Mode Default allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+ s->opt[OPT_MODE].size = max_string_size(s->scanner->caps[s->scanner->source].ColorModes);
+ s->scanner->caps[s->scanner->source].default_color = (char *)strdup(s->scanner->caps[s->scanner->source].ColorModes[0]);
+ if (!s->scanner->caps[s->scanner->source].default_color) {
+ DBG (10, "Color Mode Default allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
@@ -358,9 +617,9 @@ init_options(SANE_String_Const name, escl_sane_t *s)
s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
- s->opt[OPT_RESOLUTION].constraint.word_list = s->scanner->SupportedResolutions;
- s->val[OPT_RESOLUTION].w = s->scanner->SupportedResolutions[1];
- s->scanner->default_resolution = s->scanner->SupportedResolutions[1];
+ s->opt[OPT_RESOLUTION].constraint.word_list = s->scanner->caps[s->scanner->source].SupportedResolutions;
+ s->val[OPT_RESOLUTION].w = s->scanner->caps[s->scanner->source].SupportedResolutions[1];
+ s->scanner->caps[s->scanner->source].default_resolution = s->scanner->caps[s->scanner->source].SupportedResolutions[1];
s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
@@ -376,7 +635,7 @@ init_options(SANE_String_Const name, escl_sane_t *s)
s->val[OPT_GRAY_PREVIEW].w = SANE_FALSE;
s->opt[OPT_GEOMETRY_GROUP].title = SANE_TITLE_GEOMETRY;
- s->opt[OPT_GEOMETRY_GROUP].desc = "";
+ s->opt[OPT_GEOMETRY_GROUP].desc = SANE_DESC_GEOMETRY;
s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
@@ -385,40 +644,107 @@ init_options(SANE_String_Const name, escl_sane_t *s)
s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
- s->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL;
+ s->opt[OPT_TL_X].size = sizeof(SANE_Fixed);
+ s->opt[OPT_TL_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
- s->opt[OPT_TL_X].constraint.range = &s->x_range;
- s->val[OPT_TL_X].w = s->scanner->RiskyLeftMargin;
+ s->opt[OPT_TL_X].constraint.range = &s->x_range1;
+ s->val[OPT_TL_X].w = s->x_range1.min;
s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
- s->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL;
+ s->opt[OPT_TL_Y].size = sizeof(SANE_Fixed);
+ s->opt[OPT_TL_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
- s->opt[OPT_TL_Y].constraint.range = &s->y_range;
- s->val[OPT_TL_Y].w = s->scanner->RiskyTopMargin;
+ s->opt[OPT_TL_Y].constraint.range = &s->y_range1;
+ s->val[OPT_TL_Y].w = s->y_range1.min;
s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
- s->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL;
+ s->opt[OPT_BR_X].size = sizeof(SANE_Fixed);
+ s->opt[OPT_BR_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
- s->opt[OPT_BR_X].constraint.range = &s->x_range;
- s->val[OPT_BR_X].w = s->scanner->MaxWidth;
+ s->opt[OPT_BR_X].constraint.range = &s->x_range2;
+ s->val[OPT_BR_X].w = s->x_range2.max;
s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
- s->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL;
+ s->opt[OPT_BR_Y].size = sizeof(SANE_Fixed);
+ s->opt[OPT_BR_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
- s->opt[OPT_BR_Y].constraint.range = &s->y_range;
- s->val[OPT_BR_Y].w = s->scanner->MaxHeight;
+ s->opt[OPT_BR_Y].constraint.range = &s->y_range2;
+ s->val[OPT_BR_Y].w = s->y_range2.max;
+
+ /* OPT_SCAN_SOURCE */
+ s->opt[OPT_SCAN_SOURCE].name = SANE_NAME_SCAN_SOURCE;
+ s->opt[OPT_SCAN_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
+ s->opt[OPT_SCAN_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
+ s->opt[OPT_SCAN_SOURCE].type = SANE_TYPE_STRING;
+ s->opt[OPT_SCAN_SOURCE].size = _source_size_max(s->scanner->Sources);
+ s->opt[OPT_SCAN_SOURCE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ s->opt[OPT_SCAN_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
+ s->opt[OPT_SCAN_SOURCE].constraint.string_list = s->scanner->Sources;
+ if (s->val[OPT_SCAN_SOURCE].s)
+ free (s->val[OPT_SCAN_SOURCE].s);
+ s->val[OPT_SCAN_SOURCE].s = strdup (s->scanner->Sources[s->scanner->source]);
return (status);
}
+SANE_Status
+escl_parse_name(SANE_String_Const name, ESCL_Device *device)
+{
+ SANE_String_Const host = NULL;
+ SANE_String_Const port_str = NULL;
+ DBG(10, "escl_parse_name\n");
+ if (name == NULL || device == NULL) {
+ return SANE_STATUS_INVAL;
+ }
+
+ if (strncmp(name, "unix:", 5) == 0) {
+ SANE_String_Const socket = name + 5;
+ name = strchr(socket, ':');
+ if (name == NULL)
+ return SANE_STATUS_INVAL;
+ device->unix_socket = strndup(socket, name - socket);
+ name++;
+ }
+
+ if (strncmp(name, "https://", 8) == 0) {
+ device->https = SANE_TRUE;
+ host = name + 8;
+ } else if (strncmp(name, "http://", 7) == 0) {
+ device->https = SANE_FALSE;
+ host = name + 7;
+ } else {
+ DBG(1, "Unknown URL scheme in %s", name);
+ return SANE_STATUS_INVAL;
+ }
+
+ port_str = strchr(host, ':');
+ if (port_str == NULL) {
+ DBG(1, "Port missing from URL: %s", name);
+ return SANE_STATUS_INVAL;
+ }
+ port_str++;
+ device->port_nb = atoi(port_str);
+ if (device->port_nb < 1 || device->port_nb > 65535) {
+ DBG(1, "Invalid port number in URL: %s", name);
+ return SANE_STATUS_INVAL;
+ }
+
+ device->ip_address = strndup(host, port_str - host - 1);
+ return SANE_STATUS_GOOD;
+}
+
/**
* \fn SANE_Status sane_open(SANE_String_Const name, SANE_Handle *h)
* \brief Function that establishes a connection with the device named by 'name',
@@ -437,28 +763,45 @@ sane_open(SANE_String_Const name, SANE_Handle *h)
if (name == NULL)
return (SANE_STATUS_INVAL);
- status = escl_status(name);
- if (status != SANE_STATUS_GOOD)
- return (status);
+
+ ESCL_Device *device = calloc(1, sizeof(ESCL_Device));
+ if (device == NULL) {
+ DBG (10, "Handle device allocation failure.\n");
+ return SANE_STATUS_NO_MEM;
+ }
+ status = escl_parse_name(name, device);
+ if (status != SANE_STATUS_GOOD) {
+ escl_free_device(device);
+ return status;
+ }
+
handler = (escl_sane_t *)calloc(1, sizeof(escl_sane_t));
- if (handler == NULL)
+ if (handler == NULL) {
+ escl_free_device(device);
return (SANE_STATUS_NO_MEM);
- handler->name = strdup(name);
- handler->scanner = escl_capabilities(name, &status);
- if (status != SANE_STATUS_GOOD)
+ }
+ handler->device = device; // Handler owns device now.
+ handler->scanner = escl_capabilities(device, &status);
+ if (status != SANE_STATUS_GOOD) {
+ escl_free_handler(handler);
return (status);
- status = init_options(name, handler);
- if (status != SANE_STATUS_GOOD)
+ }
+ status = init_options(NULL, handler);
+ if (status != SANE_STATUS_GOOD) {
+ escl_free_handler(handler);
return (status);
+ }
handler->ps.depth = 8;
handler->ps.last_frame = SANE_TRUE;
handler->ps.format = SANE_FRAME_RGB;
- handler->ps.pixels_per_line = handler->val[OPT_BR_X].w;
- handler->ps.lines = handler->val[OPT_BR_Y].w;
+ handler->ps.pixels_per_line = MM_TO_PIXEL(handler->val[OPT_BR_X].w, 300.0);
+ handler->ps.lines = MM_TO_PIXEL(handler->val[OPT_BR_Y].w, 300.0);
handler->ps.bytes_per_line = handler->ps.pixels_per_line * 3;
status = sane_get_parameters(handler, 0);
- if (status != SANE_STATUS_GOOD)
+ if (status != SANE_STATUS_GOOD) {
+ escl_free_handler(handler);
return (status);
+ }
handler->cancel = SANE_FALSE;
handler->write_scan_data = SANE_FALSE;
handler->decompress_scan_data = SANE_FALSE;
@@ -483,8 +826,11 @@ sane_cancel(SANE_Handle h)
fclose(handler->scanner->tmp);
handler->scanner->tmp = NULL;
}
+ handler->scanner->work = SANE_FALSE;
handler->cancel = SANE_TRUE;
- escl_scanner(handler->name, handler->result);
+ escl_scanner(handler->device, handler->result);
+ free(handler->result);
+ handler->result = NULL;
}
/**
@@ -497,7 +843,7 @@ sane_close(SANE_Handle h)
{
DBG (10, "escl sane_close\n");
if (h != NULL) {
- free(h);
+ escl_free_handler(h);
h = NULL;
}
}
@@ -517,8 +863,8 @@ sane_get_option_descriptor(SANE_Handle h, SANE_Int n)
escl_sane_t *s = h;
if ((unsigned) n >= NUM_OPTIONS || n < 0)
- return (0);
- return (s->opt + n);
+ return (0);
+ return (&s->opt[n]);
}
/**
@@ -541,62 +887,92 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int
escl_sane_t *handler = h;
if (i)
- *i = 0;
+ *i = 0;
if (n >= NUM_OPTIONS || n < 0)
- return (SANE_STATUS_INVAL);
+ return (SANE_STATUS_INVAL);
if (a == SANE_ACTION_GET_VALUE) {
- switch (n) {
- case OPT_NUM_OPTS:
- case OPT_RESOLUTION:
- case OPT_TL_X:
- case OPT_TL_Y:
- case OPT_BR_X:
- case OPT_BR_Y:
- case OPT_PREVIEW:
- case OPT_GRAY_PREVIEW:
- *(SANE_Word *) v = handler->val[n].w;
- break;
- case OPT_MODE:
- strcpy (v, handler->val[n].s);
- break;
- case OPT_MODE_GROUP:
- default:
- break;
- }
- return (SANE_STATUS_GOOD);
+ switch (n) {
+ case OPT_TL_X:
+ case OPT_TL_Y:
+ case OPT_BR_X:
+ case OPT_BR_Y:
+ case OPT_NUM_OPTS:
+ case OPT_RESOLUTION:
+ case OPT_PREVIEW:
+ case OPT_GRAY_PREVIEW:
+ *(SANE_Word *) v = handler->val[n].w;
+ break;
+ case OPT_SCAN_SOURCE:
+ case OPT_MODE:
+ strcpy (v, handler->val[n].s);
+ break;
+ case OPT_MODE_GROUP:
+ default:
+ break;
+ }
+ return (SANE_STATUS_GOOD);
}
if (a == SANE_ACTION_SET_VALUE) {
- switch (n) {
- case OPT_TL_X:
- case OPT_TL_Y:
- case OPT_BR_X:
- case OPT_BR_Y:
- case OPT_PREVIEW:
- case OPT_GRAY_PREVIEW:
- handler->val[n].w = *(SANE_Word *) v;
- if (i && handler->val[n].w != *(SANE_Word *) v)
- *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
- handler->val[n].w = *(SANE_Word *) v;
- break;
- case OPT_RESOLUTION:
- handler->val[n].w = *(SANE_Word *) v;
- if (i)
- *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
- break;
- case OPT_MODE:
- if (handler->val[n].s)
- free (handler->val[n].s);
- handler->val[n].s = strdup (v);
- if (i)
- *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
- break;
- default:
- break;
- }
+ switch (n) {
+ case OPT_TL_X:
+ case OPT_TL_Y:
+ case OPT_BR_X:
+ case OPT_BR_Y:
+ case OPT_NUM_OPTS:
+ case OPT_RESOLUTION:
+ case OPT_PREVIEW:
+ case OPT_GRAY_PREVIEW:
+ handler->val[n].w = *(SANE_Word *) v;
+ if (i)
+ *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
+ break;
+ case OPT_SCAN_SOURCE:
+ DBG(10, "SET OPT_SCAN_SOURCE(%s)\n", (SANE_String_Const)v);
+ init_options((SANE_String_Const)v, handler);
+ if (i)
+ *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
+ break;
+ case OPT_MODE:
+ if (handler->val[n].s)
+ free (handler->val[n].s);
+ handler->val[n].s = strdup (v);
+ if (!handler->val[n].s) {
+ DBG (10, "OPT_MODE allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+ if (i)
+ *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
+ break;
+ default:
+ break;
+ }
}
return (SANE_STATUS_GOOD);
}
+static SANE_Bool
+_go_next_page(SANE_Status status,
+ SANE_Status job)
+{
+ // Thank's Alexander Pevzner (pzz@apevzner.com)
+ SANE_Status st = SANE_STATUS_NO_DOCS;
+ switch (status) {
+ case SANE_STATUS_GOOD:
+ case SANE_STATUS_UNSUPPORTED:
+ case SANE_STATUS_DEVICE_BUSY: {
+ DBG(10, "eSCL : Test next page\n");
+ if (job != SANE_STATUS_GOOD) {
+ DBG(10, "eSCL : Go next page\n");
+ st = SANE_STATUS_GOOD;
+ }
+ break;
+ }
+ default:
+ DBG(10, "eSCL : No next page\n");
+ }
+ return st;
+}
+
/**
* \fn SANE_Status sane_start(SANE_Handle h)
* \brief Function that initiates aquisition of an image from the device represented by handle 'h'.
@@ -614,70 +990,137 @@ sane_start(SANE_Handle h)
int he = 0;
int bps = 0;
- if (handler->name == NULL)
+ if (handler->device == NULL) {
+ DBG(1, "Missing handler device.\n");
return (SANE_STATUS_INVAL);
+ }
handler->cancel = SANE_FALSE;
handler->write_scan_data = SANE_FALSE;
handler->decompress_scan_data = SANE_FALSE;
handler->end_read = SANE_FALSE;
- handler->scanner->height = handler->val[OPT_BR_Y].w;
- handler->scanner->width = handler->val[OPT_BR_X].w;
- handler->scanner->pos_x = handler->val[OPT_TL_X].w;
- handler->scanner->pos_y = handler->val[OPT_TL_Y].w;
- if(handler->scanner->default_color)
- free(handler->scanner->default_color);
- if (handler->val[OPT_PREVIEW].w == SANE_TRUE)
- {
- int i = 0, val = 9999;;
- if (handler->val[OPT_GRAY_PREVIEW].w == SANE_TRUE ||
- !strncasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY, 3))
- handler->scanner->default_color = strdup("Grayscale8");
+ if (handler->scanner->work == SANE_FALSE) {
+ SANE_Status st = escl_status(handler->device,
+ handler->scanner->source,
+ NULL,
+ NULL);
+ if (st != SANE_STATUS_GOOD)
+ return st;
+ if(handler->scanner->caps[handler->scanner->source].default_color)
+ free(handler->scanner->caps[handler->scanner->source].default_color);
+ if (handler->val[OPT_PREVIEW].w == SANE_TRUE)
+ {
+ int i = 0, val = 9999;;
+ if (handler->val[OPT_GRAY_PREVIEW].w == SANE_TRUE ||
+ !strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY))
+ handler->scanner->caps[handler->scanner->source].default_color =
+ strdup("Grayscale8");
+ else
+ handler->scanner->caps[handler->scanner->source].default_color =
+ strdup("RGB24");
+ if (!handler->scanner->caps[handler->scanner->source].default_color) {
+ DBG (10, "Default Color allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+ for (i = 1; i < handler->scanner->caps[handler->scanner->source].SupportedResolutionsSize; i++)
+ {
+ if (val > handler->scanner->caps[handler->scanner->source].SupportedResolutions[i])
+ val = handler->scanner->caps[handler->scanner->source].SupportedResolutions[i];
+ }
+ handler->scanner->caps[handler->scanner->source].default_resolution = val;
+ }
else
- handler->scanner->default_color = strdup("RGB24");
- for (i = 1; i < handler->scanner->SupportedResolutionsSize; i++)
{
- if (val > handler->scanner->SupportedResolutions[i])
- val = handler->scanner->SupportedResolutions[i];
+ handler->scanner->caps[handler->scanner->source].default_resolution =
+ handler->val[OPT_RESOLUTION].w;
+ if (!strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY))
+ handler->scanner->caps[handler->scanner->source].default_color = strdup("Grayscale8");
+ else if (!strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART))
+ handler->scanner->caps[handler->scanner->source].default_color =
+ strdup("BlackAndWhite1");
+ else
+ handler->scanner->caps[handler->scanner->source].default_color =
+ strdup("RGB24");
}
- handler->scanner->default_resolution = val;
+ handler->scanner->caps[handler->scanner->source].height =
+ MM_TO_PIXEL(handler->val[OPT_BR_Y].w, 300.0);
+ handler->scanner->caps[handler->scanner->source].width =
+ MM_TO_PIXEL(handler->val[OPT_BR_X].w, 300.0);;
+ if (handler->x_range1.min == handler->val[OPT_TL_X].w)
+ handler->scanner->caps[handler->scanner->source].pos_x = 0;
+ else
+ handler->scanner->caps[handler->scanner->source].pos_x =
+ MM_TO_PIXEL((handler->val[OPT_TL_X].w - handler->x_range1.min),
+ 300.0);
+ if (handler->y_range1.min == handler->val[OPT_TL_X].w)
+ handler->scanner->caps[handler->scanner->source].pos_y = 0;
+ else
+ handler->scanner->caps[handler->scanner->source].pos_y =
+ MM_TO_PIXEL((handler->val[OPT_TL_Y].w - handler->y_range1.min),
+ 300.0);
+ DBG(10, "Calculate Size Image [%dx%d|%dx%d]\n",
+ handler->scanner->caps[handler->scanner->source].pos_x,
+ handler->scanner->caps[handler->scanner->source].pos_y,
+ handler->scanner->caps[handler->scanner->source].width,
+ handler->scanner->caps[handler->scanner->source].height);
+ if (!handler->scanner->caps[handler->scanner->source].default_color) {
+ DBG (10, "Default Color allocation failure.\n");
+ return (SANE_STATUS_NO_MEM);
+ }
+ handler->result = escl_newjob(handler->scanner, handler->device, &status);
+ if (status != SANE_STATUS_GOOD)
+ return (status);
}
else
{
- handler->scanner->default_resolution = handler->val[OPT_RESOLUTION].w;
- if (!strncasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY, 3))
- handler->scanner->default_color = strdup("Grayscale8");
- else
- handler->scanner->default_color = strdup("RGB24");
+ SANE_Status job = SANE_STATUS_UNSUPPORTED;
+ SANE_Status st = escl_status(handler->device,
+ handler->scanner->source,
+ handler->result,
+ &job);
+ DBG(10, "eSCL : command returned status %s\n", sane_strstatus(st));
+ if (_go_next_page(st, job) != SANE_STATUS_GOOD)
+ {
+ handler->scanner->work = SANE_FALSE;
+ return SANE_STATUS_NO_DOCS;
+ }
}
- handler->result = escl_newjob(handler->scanner, handler->name, &status);
+ status = escl_scan(handler->scanner, handler->device, handler->result);
if (status != SANE_STATUS_GOOD)
- return (status);
- status = escl_scan(handler->scanner, handler->name, handler->result);
- if (status != SANE_STATUS_GOOD)
- return (status);
- if (!strcmp(handler->scanner->default_format, "image/jpeg"))
+ return (status);
+ if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "image/jpeg"))
{
status = get_JPEG_data(handler->scanner, &w, &he, &bps);
}
- else if (!strcmp(handler->scanner->default_format, "image/png"))
+ else if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "image/png"))
{
status = get_PNG_data(handler->scanner, &w, &he, &bps);
}
- else if (!strcmp(handler->scanner->default_format, "image/tiff"))
+ else if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "image/tiff"))
{
status = get_TIFF_data(handler->scanner, &w, &he, &bps);
}
- else
- return SANE_STATUS_INVAL;
+ else if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "application/pdf"))
+ {
+ status = get_PDF_data(handler->scanner, &w, &he, &bps);
+ }
+ else {
+ DBG(10, "Unknow image format\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ DBG(10, "2-Size Image (%ld)[%dx%d|%dx%d]\n", handler->scanner->img_size, 0, 0, w, he);
if (status != SANE_STATUS_GOOD)
- return (status);
+ return (status);
handler->ps.depth = 8;
handler->ps.pixels_per_line = w;
handler->ps.lines = he;
handler->ps.bytes_per_line = w * bps;
handler->ps.last_frame = SANE_TRUE;
handler->ps.format = SANE_FRAME_RGB;
+ handler->scanner->work = SANE_FALSE;
+// DBG(10, "NEXT Frame [%s]\n", (handler->ps.last_frame ? "Non" : "Oui"));
+ DBG(10, "Real Size Image [%dx%d|%dx%d]\n", 0, 0, w, he);
return (status);
}
@@ -700,7 +1143,7 @@ sane_get_parameters(SANE_Handle h, SANE_Parameters *p)
return (status);
if (p != NULL) {
p->depth = 8;
- p->last_frame = SANE_TRUE;
+ p->last_frame = handler->ps.last_frame;
p->format = SANE_FRAME_RGB;
p->pixels_per_line = handler->ps.pixels_per_line;
p->lines = handler->ps.lines;
@@ -729,6 +1172,7 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len)
if (!handler | !buf | !len)
return (SANE_STATUS_INVAL);
+
if (handler->cancel)
return (SANE_STATUS_CANCELLED);
if (!handler->write_scan_data)
@@ -756,10 +1200,23 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len)
}
}
else {
+ SANE_Status job = SANE_STATUS_UNSUPPORTED;
*len = 0;
free(handler->scanner->img_data);
handler->scanner->img_data = NULL;
- return (SANE_STATUS_EOF);
+ if (handler->scanner->source != PLATEN) {
+ SANE_Bool next_page = SANE_FALSE;
+ SANE_Status st = escl_status(handler->device,
+ handler->scanner->source,
+ handler->result,
+ &job);
+ DBG(10, "eSCL : command returned status %s\n", sane_strstatus(st));
+ if (_go_next_page(st, job) == SANE_STATUS_GOOD)
+ next_page = SANE_TRUE;
+ handler->scanner->work = SANE_TRUE;
+ handler->ps.last_frame = !next_page;
+ }
+ return SANE_STATUS_EOF;
}
return (SANE_STATUS_GOOD);
}
@@ -775,3 +1232,39 @@ sane_set_io_mode(SANE_Handle __sane_unused__ handle, SANE_Bool __sane_unused__ n
{
return (SANE_STATUS_UNSUPPORTED);
}
+
+/**
+ * \fn void escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path)
+ * \brief Uses the device info in 'device' and the path from 'path' to construct
+ * a full URL. Sets this URL and any necessary connection options into
+ * 'handle'.
+ */
+void
+escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path)
+{
+ int url_len;
+ char *url;
+
+ url_len = snprintf(NULL, 0, "%s://%s:%d%s",
+ (device->https ? "https" : "http"), device->ip_address,
+ device->port_nb, path);
+ url_len++;
+ url = (char *)malloc(url_len);
+ snprintf(url, url_len, "%s://%s:%d%s",
+ (device->https ? "https" : "http"), device->ip_address,
+ device->port_nb, path);
+
+ DBG( 1, "escl_curl_url: URL: %s\n", url );
+ curl_easy_setopt(handle, CURLOPT_URL, url);
+ free(url);
+ if (device->https) {
+ DBG( 1, "Ignoring safety certificates, use https\n");
+ curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);
+ curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);
+ }
+ if (device->unix_socket != NULL) {
+ DBG( 1, "Using local socket %s\n", device->unix_socket );
+ curl_easy_setopt(handle, CURLOPT_UNIX_SOCKET_PATH,
+ device->unix_socket);
+ }
+}
diff --git a/backend/escl/escl.h b/backend/escl/escl.h
index 82910bd..53ce7c7 100644
--- a/backend/escl/escl.h
+++ b/backend/escl/escl.h
@@ -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
diff --git a/backend/escl/escl_capabilities.c b/backend/escl/escl_capabilities.c
index 690ff1e..fdd5cfe 100644
--- a/backend/escl/escl_capabilities.c
+++ b/backend/escl/escl_capabilities.c
@@ -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"))
+ {
+ have_tiff = SANE_TRUE;
+ }
+#endif
+#if(defined HAVE_POPPLER_GLIB)
+ else if(type == PLATEN && !strcmp(scanner->caps[type].DocumentFormats[i], "application/pdf"))
{
- if (scanner->default_format)
- free(scanner->default_format);
- scanner->default_format = strdup("image/tiff");
+ 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);
}
diff --git a/backend/escl/escl_crop.c b/backend/escl/escl_crop.c
new file mode 100644
index 0000000..8740d22
--- /dev/null
+++ b/backend/escl/escl_crop.c
@@ -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;
+}
diff --git a/backend/escl/escl_jpeg.c b/backend/escl/escl_jpeg.c
index d6287ef..8d6b6b6 100644
--- a/backend/escl/escl_jpeg.c
+++ b/backend/escl/escl_jpeg.c
@@ -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);
diff --git a/backend/escl/escl_mupdf.c b/backend/escl/escl_mupdf.c
new file mode 100644
index 0000000..9399218
--- /dev/null
+++ b/backend/escl/escl_mupdf.c
@@ -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
diff --git a/backend/escl/escl_newjob.c b/backend/escl/escl_newjob.c
index 279b9df..ee8c03c 100644
--- a/backend/escl/escl_newjob.c
+++ b/backend/escl/escl_newjob.c
@@ -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 {
diff --git a/backend/escl/escl_pdf.c b/backend/escl/escl_pdf.c
new file mode 100644
index 0000000..ae85a3a
--- /dev/null
+++ b/backend/escl/escl_pdf.c
@@ -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
diff --git a/backend/escl/escl_png.c b/backend/escl/escl_png.c
index 18f6f35..cf92449 100644
--- a/backend/escl/escl_png.c
+++ b/backend/escl/escl_png.c
@@ -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;
+ components = 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);
+ 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);
diff --git a/backend/escl/escl_reset.c b/backend/escl/escl_reset.c
index 7722d89..64d779a 100644
--- a/backend/escl/escl_reset.c
+++ b/backend/escl/escl_reset.c
@@ -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;
}
}
diff --git a/backend/escl/escl_scan.c b/backend/escl/escl_scan.c
index 8f077a1..9fce801 100644
--- a/backend/escl/escl_scan.c
+++ b/backend/escl/escl_scan.c
@@ -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);
}
diff --git a/backend/escl/escl_status.c b/backend/escl/escl_status.c
index 68b51dc..7b98566 100644
--- a/backend/escl/escl_status.c
+++ b/backend/escl/escl_status.c
@@ -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, "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);
+ }
+ }
+ }
+ }
+ 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)
- x = 1;
+ if (strcmp((const char *)node->name, "State") == 0) {
+ DBG(10, "State\t");
+ const char *state = (const char *)xmlNodeGetContent(node);
+ if (!strcmp(state, "Idle")) {
+ DBG(10, "Idle SANE_STATUS_GOOD\n");
+ *platen = SANE_STATUS_GOOD;
+ } else if (!strcmp(state, "Processing")) {
+ DBG(10, "Processing SANE_STATUS_DEVICE_BUSY\n");
+ *platen = SANE_STATUS_DEVICE_BUSY;
+ } else {
+ DBG(10, "%s SANE_STATUS_UNSUPPORTED\n", state);
+ *platen = SANE_STATUS_UNSUPPORTED;
+ }
+ }
+ // Thank's Alexander Pevzner (pzz@apevzner.com)
+ else if (adf && strcmp((const char *)node->name, "AdfState") == 0) {
+ const char *state = (const char *)xmlNodeGetContent(node);
+ if (!strcmp(state, "ScannerAdfLoaded")){
+ DBG(10, "ScannerAdfLoaded SANE_STATUS_GOOD\n");
+ *adf = SANE_STATUS_GOOD;
+ } else if (!strcmp(state, "ScannerAdfJam")) {
+ DBG(10, "ScannerAdfJam SANE_STATUS_JAMMED\n");
+ *adf = SANE_STATUS_JAMMED;
+ } else if (!strcmp(state, "ScannerAdfDoorOpen")) {
+ DBG(10, "ScannerAdfDoorOpen SANE_STATUS_COVER_OPEN\n");
+ *adf = SANE_STATUS_COVER_OPEN;
+ } else if (!strcmp(state, "ScannerAdfProcessing")) {
+ /* Kyocera version */
+ DBG(10, "ScannerAdfProcessing SANE_STATUS_NO_DOC\n");
+ *adf = SANE_STATUS_NO_DOCS;
+ } else if (!strcmp(state, "ScannerAdfEmpty")) {
+ DBG(10, "ScannerAdfEmpty SANE_STATUS_NO_DOCS\n");
+ /* Cannon TR4500, EPSON XP-7100 */
+ *adf = SANE_STATUS_NO_DOCS;
+ } else {
+ DBG(10, "%s SANE_STATUS_NO_DOCS\n", state);
+ *adf = SANE_STATUS_UNSUPPORTED;
+ }
+ }
+ else if (jobId && job && strcmp((const char *)node->name, "JobUri") == 0) {
+ if (strstr((const char *)xmlNodeGetContent(node), jobId)) {
+ print_xml_job_status(node, job, image);
+ }
+ }
}
- if (x == 1 && strcmp((const char *)xmlNodeGetContent(node), "Idle") == 0)
- *status = SANE_STATUS_GOOD;
}
- print_xml_s(node->children, status);
+ 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);
}
diff --git a/backend/escl/escl_tiff.c b/backend/escl/escl_tiff.c
index 52aec20..98bc5f3 100644
--- a/backend/escl/escl_tiff.c
+++ b/backend/escl/escl_tiff.c
@@ -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
diff --git a/backend/fujitsu-scsi.h b/backend/fujitsu-scsi.h
index 38425a6..c2b28dd 100644
--- a/backend/fujitsu-scsi.h
+++ b/backend/fujitsu-scsi.h
@@ -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)
diff --git a/backend/fujitsu.c b/backend/fujitsu.c
index 5dc466c..d24975e 100644
--- a/backend/fujitsu.c
+++ b/backend/fujitsu.c
@@ -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,
diff --git a/backend/fujitsu.conf.in b/backend/fujitsu.conf.in
index 4f2b1a9..8e2115f 100644
--- a/backend/fujitsu.conf.in
+++ b/backend/fujitsu.conf.in
@@ -255,3 +255,12 @@ usb 0x04c5 0x1522
#ScanSnap iX1500
usb 0x04c5 0x159f
+
+#fi-800R
+usb 0x04c5 0x15fc
+
+#fi-7900
+usb 0x04c5 0x160a
+
+#fi-7800
+usb 0x04c5 0x160b
diff --git a/backend/fujitsu.h b/backend/fujitsu.h
index 4c20474..3b3ce54 100644
--- a/backend/fujitsu.h
+++ b/backend/fujitsu.h
@@ -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
diff --git a/backend/genesys.conf.in b/backend/genesys.conf.in
index 786ccd5..8268da3 100644
--- a/backend/genesys.conf.in
+++ b/backend/genesys.conf.in
@@ -39,6 +39,9 @@ usb 0x04a9 0x221c
# Canon LiDE 80
usb 0x04a9 0x2214
+# Canon LiDE 90
+usb 0x04a9 0x1900
+
# Canon 4400F
usb 0x04a9 0x2228
@@ -124,15 +127,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
diff --git a/backend/genesys/buffer.cpp b/backend/genesys/buffer.cpp
deleted file mode 100644
index f17e361..0000000
--- a/backend/genesys/buffer.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/* sane - Scanner Access Now Easy.
-
- Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
-
- This file is part of the SANE package.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA.
-
- As a special exception, the authors of SANE give permission for
- additional uses of the libraries contained in this release of SANE.
-
- The exception is that, if you link a SANE library with other files
- to produce an executable, this does not by itself cause the
- resulting executable to be covered by the GNU General Public
- License. Your use of that executable is in no way restricted on
- account of linking the SANE library code into it.
-
- This exception does not, however, invalidate any other reasons why
- the executable file might be covered by the GNU General Public
- License.
-
- If you submit changes to SANE to the maintainers to be included in
- a subsequent release, you agree by submitting the changes that
- those changes may be distributed with this exception intact.
-
- If you write modifications of your own for SANE, it is your choice
- whether to permit this exception to apply to your modifications.
- If you do not wish that, delete this exception notice.
-*/
-
-#include "buffer.h"
-#include <cstring>
-#include <stdexcept>
-
-namespace genesys {
-
-void Genesys_Buffer::alloc(std::size_t size)
-{
- buffer_.resize(size);
- avail_ = 0;
- pos_ = 0;
-}
-
-void Genesys_Buffer::clear()
-{
- buffer_.clear();
- avail_ = 0;
- pos_ = 0;
-}
-
-void Genesys_Buffer::reset()
-{
- avail_ = 0;
- pos_ = 0;
-}
-
-std::uint8_t* Genesys_Buffer::get_write_pos(std::size_t size)
-{
- if (avail_ + size > buffer_.size())
- return nullptr;
- if (pos_ + avail_ + size > buffer_.size())
- {
- std::memmove(buffer_.data(), buffer_.data() + pos_, avail_);
- pos_ = 0;
- }
- return buffer_.data() + pos_ + avail_;
-}
-
-std::uint8_t* Genesys_Buffer::get_read_pos()
-{
- return buffer_.data() + pos_;
-}
-
-void Genesys_Buffer::produce(std::size_t size)
-{
- if (size > buffer_.size() - avail_)
- throw std::runtime_error("buffer size exceeded");
- avail_ += size;
-}
-
-void Genesys_Buffer::consume(std::size_t size)
-{
- if (size > avail_)
- throw std::runtime_error("no more data in buffer");
- avail_ -= size;
- pos_ += size;
-}
-
-} // namespace genesys
diff --git a/backend/genesys/buffer.h b/backend/genesys/buffer.h
deleted file mode 100644
index e9c889b..0000000
--- a/backend/genesys/buffer.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* sane - Scanner Access Now Easy.
-
- Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
-
- This file is part of the SANE package.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA.
-
- As a special exception, the authors of SANE give permission for
- additional uses of the libraries contained in this release of SANE.
-
- The exception is that, if you link a SANE library with other files
- to produce an executable, this does not by itself cause the
- resulting executable to be covered by the GNU General Public
- License. Your use of that executable is in no way restricted on
- account of linking the SANE library code into it.
-
- This exception does not, however, invalidate any other reasons why
- the executable file might be covered by the GNU General Public
- License.
-
- If you submit changes to SANE to the maintainers to be included in
- a subsequent release, you agree by submitting the changes that
- those changes may be distributed with this exception intact.
-
- If you write modifications of your own for SANE, it is your choice
- whether to permit this exception to apply to your modifications.
- If you do not wish that, delete this exception notice.
-*/
-
-#ifndef BACKEND_GENESYS_BUFFER_H
-#define BACKEND_GENESYS_BUFFER_H
-
-#include <vector>
-#include <cstddef>
-#include <cstdint>
-
-namespace genesys {
-
-/* A FIFO buffer. Note, that this is _not_ a ringbuffer.
- if we need a block which does not fit at the end of our available data,
- we move the available data to the beginning.
-*/
-struct Genesys_Buffer
-{
- Genesys_Buffer() = default;
-
- std::size_t size() const { return buffer_.size(); }
- std::size_t avail() const { return avail_; }
- std::size_t pos() const { return pos_; }
-
- // TODO: refactor code that uses this function to no longer use it
- void set_pos(std::size_t pos) { pos_ = pos; }
-
- void alloc(std::size_t size);
- void clear();
-
- void reset();
-
- std::uint8_t* get_write_pos(std::size_t size);
- std::uint8_t* get_read_pos(); // TODO: mark as const
-
- void produce(std::size_t size);
- void consume(std::size_t size);
-
-private:
- std::vector<std::uint8_t> buffer_;
- // current position in read buffer
- std::size_t pos_ = 0;
- // data bytes currently in buffer
- std::size_t avail_ = 0;
-};
-
-} // namespace genesys
-
-#endif // BACKEND_GENESYS_BUFFER_H
diff --git a/backend/genesys/calibration.h b/backend/genesys/calibration.h
index f14aaa3..81d94ea 100644
--- a/backend/genesys/calibration.h
+++ b/backend/genesys/calibration.h
@@ -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);
diff --git a/backend/genesys/command_set.h b/backend/genesys/command_set.h
index ab3a4b6..056cba8 100644
--- a/backend/genesys/command_set.h
+++ b/backend/genesys/command_set.h
@@ -67,14 +67,10 @@ public:
virtual void init(Genesys_Device* dev) const = 0;
virtual void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs, int* channels,
- int* total_size) const = 0;
+ Genesys_Register_Set* regs) const = 0;
- virtual void init_regs_for_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;
/** Set up registers for a scan. Similar to init_regs_for_scan except that the session is
already computed from the session
@@ -98,7 +94,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,
@@ -112,15 +107,10 @@ public:
// Updates hardware sensor information in Genesys_Scanner.val[].
virtual void update_hardware_sensors(struct Genesys_Scanner* s) const = 0;
- /** Whether the scanner needs to call update_home_sensor_gpio before reading the status of the
- home sensor. On some chipsets this is unreliable until update_home_sensor_gpio() is called.
+ /** Needed on some chipsets before reading the status of the home sensor as the sensor may be
+ controlled by additional GPIO registers.
*/
- virtual bool needs_update_home_sensor_gpio() const { return false; }
-
- /** Needed on some chipsets before reading the status of the home sensor to make this operation
- reliable.
- */
- virtual void update_home_sensor_gpio(Genesys_Device& dev) const { (void) dev; }
+ virtual void update_home_sensor_gpio(Genesys_Device& dev) const = 0;
// functions for sheetfed scanners
@@ -134,14 +124,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;
/// write shading data calibration to ASIC
virtual void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
@@ -159,6 +141,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
diff --git a/backend/genesys/command_set_common.cpp b/backend/genesys/command_set_common.cpp
new file mode 100644
index 0000000..381404e
--- /dev/null
+++ b/backend/genesys/command_set_common.cpp
@@ -0,0 +1,248 @@
+/* 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_5600F, 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
diff --git a/backend/genesys/command_set_common.h b/backend/genesys/command_set_common.h
new file mode 100644
index 0000000..784fcd7
--- /dev/null
+++ b/backend/genesys/command_set_common.h
@@ -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
diff --git a/backend/genesys/conv.cpp b/backend/genesys/conv.cpp
deleted file mode 100644
index a87c463..0000000
--- a/backend/genesys/conv.cpp
+++ /dev/null
@@ -1,238 +0,0 @@
-/* sane - Scanner Access Now Easy.
-
- Copyright (C) 2005, 2006 Pierre Willenbrock <pierre@pirsoft.dnsalias.org>
- Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr>
-
- This file is part of the SANE package.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA.
-
- As a special exception, the authors of SANE give permission for
- additional uses of the libraries contained in this release of SANE.
-
- The exception is that, if you link a SANE library with other files
- to produce an executable, this does not by itself cause the
- resulting executable to be covered by the GNU General Public
- License. Your use of that executable is in no way restricted on
- account of linking the SANE library code into it.
-
- This exception does not, however, invalidate any other reasons why
- the executable file might be covered by the GNU General Public
- License.
-
- If you submit changes to SANE to the maintainers to be included in
- a subsequent release, you agree by submitting the changes that
- those changes may be distributed with this exception intact.
-
- If you write modifications of your own for SANE, it is your choice
- whether to permit this exception to apply to your modifications.
- If you do not wish that, delete this exception notice.
-*/
-
-#define DEBUG_DECLARE_ONLY
-
-#include "conv.h"
-#include "sane/sanei_magic.h"
-
-namespace genesys {
-
-/**
- * uses the threshold/threshold_curve to control software binarization
- * This code was taken from the epjistsu backend by m. allan noah
- * @param dev device set up for the scan
- * @param src pointer to raw data
- * @param dst pointer where to store result
- * @param width width of the processed line
- * */
-void binarize_line(Genesys_Device* dev, std::uint8_t* src, std::uint8_t* dst, int width)
-{
- DBG_HELPER(dbg);
- int j, windowX, sum = 0;
- int thresh;
- int offset, addCol, dropCol;
- unsigned char mask;
-
- int x;
- std::uint8_t min, max;
-
- /* normalize line */
- min = 255;
- max = 0;
- for (x = 0; x < width; x++)
- {
- if (src[x] > max)
- {
- max = src[x];
- }
- if (src[x] < min)
- {
- min = src[x];
- }
- }
-
- /* safeguard against dark or white areas */
- if(min>80)
- min=0;
- if(max<80)
- max=255;
- for (x = 0; x < width; x++)
- {
- src[x] = ((src[x] - min) * 255) / (max - min);
- }
-
- /* ~1mm works best, but the window needs to have odd # of pixels */
- windowX = (6 * dev->settings.xres) / 150;
- if (!(windowX % 2))
- windowX++;
-
- /* second, prefill the sliding sum */
- for (j = 0; j < windowX; j++)
- sum += src[j];
-
- /* third, walk the input buffer, update the sliding sum, */
- /* determine threshold, output bits */
- for (j = 0; j < width; j++)
- {
- /* output image location */
- offset = j % 8;
- mask = 0x80 >> offset;
- thresh = dev->settings.threshold;
-
- /* move sum/update threshold only if there is a curve */
- if (dev->settings.threshold_curve)
- {
- addCol = j + windowX / 2;
- dropCol = addCol - windowX;
-
- if (dropCol >= 0 && addCol < width)
- {
- sum -= src[dropCol];
- sum += src[addCol];
- }
- thresh = dev->lineart_lut[sum / windowX];
- }
-
- /* use average to lookup threshold */
- if (src[j] > thresh)
- *dst &= ~mask; /* white */
- else
- *dst |= mask; /* black */
-
- if (offset == 7)
- dst++;
- }
-}
-
-/**
- * software lineart using data from a 8 bit gray scan. We assume true gray
- * or monochrome scan as input.
- */
-void genesys_gray_lineart(Genesys_Device* dev,
- std::uint8_t* src_data, std::uint8_t* dst_data,
- std::size_t pixels, std::size_t lines, std::uint8_t threshold)
-{
- DBG_HELPER(dbg);
- std::size_t y;
-
- DBG(DBG_io2, "%s: converting %zu lines of %zu pixels\n", __func__, lines, pixels);
- DBG(DBG_io2, "%s: threshold=%d\n", __func__, threshold);
-
- for (y = 0; y < lines; y++)
- {
- binarize_line (dev, src_data + y * pixels, dst_data, pixels);
- dst_data += pixels / 8;
- }
-}
-
-/** Look in image for likely left/right/bottom paper edges, then crop image.
- */
-void genesys_crop(Genesys_Scanner* s)
-{
- DBG_HELPER(dbg);
- Genesys_Device *dev = s->dev;
- int top = 0;
- int bottom = 0;
- int left = 0;
- int right = 0;
-
- // first find edges if any
- TIE(sanei_magic_findEdges(&s->params, dev->img_buffer.data(),
- dev->settings.xres, dev->settings.yres,
- &top, &bottom, &left, &right));
-
- DBG (DBG_io, "%s: t:%d b:%d l:%d r:%d\n", __func__, top, bottom, left,
- right);
-
- // now crop the image
- TIE(sanei_magic_crop (&(s->params), dev->img_buffer.data(), top, bottom, left, right));
-
- /* update counters to new image size */
- dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines;
-}
-
-/** Look in image for likely upper and left paper edges, then rotate
- * image so that upper left corner of paper is upper left of image.
- */
-void genesys_deskew(Genesys_Scanner *s, const Genesys_Sensor& sensor)
-{
- DBG_HELPER(dbg);
- Genesys_Device *dev = s->dev;
-
- int x = 0, y = 0, bg;
- double slope = 0;
-
- bg=0;
- if(s->params.format==SANE_FRAME_GRAY && s->params.depth == 1)
- {
- bg=0xff;
- }
- TIE(sanei_magic_findSkew(&s->params, dev->img_buffer.data(),
- sensor.optical_res, sensor.optical_res,
- &x, &y, &slope));
-
- DBG(DBG_info, "%s: slope=%f => %f\n", __func__, slope, slope * 180 / M_PI);
-
- // rotate image slope is in [-PI/2,PI/2]. Positive values rotate trigonometric direction wise
- TIE(sanei_magic_rotate(&s->params, dev->img_buffer.data(),
- x, y, slope, bg));
-}
-
-/** remove lone dots
- */
-void genesys_despeck(Genesys_Scanner* s)
-{
- DBG_HELPER(dbg);
- TIE(sanei_magic_despeck(&s->params, s->dev->img_buffer.data(), s->despeck));
-}
-
-/** Look if image needs rotation and apply it
- * */
-void genesys_derotate(Genesys_Scanner* s)
-{
- DBG_HELPER(dbg);
- int angle = 0;
-
- TIE(sanei_magic_findTurn(&s->params, s->dev->img_buffer.data(),
- s->resolution, s->resolution, &angle));
-
- // apply rotation angle found
- TIE(sanei_magic_turn(&s->params, s->dev->img_buffer.data(), angle));
-
- // update counters to new image size
- s->dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines;
-}
-
-} // namespace genesys
diff --git a/backend/genesys/conv.h b/backend/genesys/conv.h
deleted file mode 100644
index 446a80d..0000000
--- a/backend/genesys/conv.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* sane - Scanner Access Now Easy.
-
- Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
-
- This file is part of the SANE package.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA.
-
- As a special exception, the authors of SANE give permission for
- additional uses of the libraries contained in this release of SANE.
-
- The exception is that, if you link a SANE library with other files
- to produce an executable, this does not by itself cause the
- resulting executable to be covered by the GNU General Public
- License. Your use of that executable is in no way restricted on
- account of linking the SANE library code into it.
-
- This exception does not, however, invalidate any other reasons why
- the executable file might be covered by the GNU General Public
- License.
-
- If you submit changes to SANE to the maintainers to be included in
- a subsequent release, you agree by submitting the changes that
- those changes may be distributed with this exception intact.
-
- If you write modifications of your own for SANE, it is your choice
- whether to permit this exception to apply to your modifications.
- If you do not wish that, delete this exception notice.
-*/
-
-#ifndef BACKEND_GENESYS_CONV_H
-#define BACKEND_GENESYS_CONV_H
-
-#include "device.h"
-#include "sensor.h"
-#include "genesys.h"
-
-namespace genesys {
-
-void binarize_line(Genesys_Device* dev, std::uint8_t* src, std::uint8_t* dst, int width);
-
-void genesys_gray_lineart(Genesys_Device* dev,
- std::uint8_t* src_data, std::uint8_t* dst_data,
- std::size_t pixels, size_t lines, std::uint8_t threshold);
-
-void genesys_crop(Genesys_Scanner* s);
-
-void genesys_deskew(Genesys_Scanner *s, const Genesys_Sensor& sensor);
-
-void genesys_despeck(Genesys_Scanner* s);
-
-void genesys_derotate(Genesys_Scanner* s);
-
-} // namespace genesys
-
-#endif // BACKEND_GENESYS_CONV_H
diff --git a/backend/genesys/device.cpp b/backend/genesys/device.cpp
index ba035fd..95bede8 100644
--- a/backend/genesys/device.cpp
+++ b/backend/genesys/device.cpp
@@ -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();
@@ -87,10 +102,6 @@ Genesys_Device::~Genesys_Device()
void Genesys_Device::clear()
{
- read_buffer.clear();
- binarize_buffer.clear();
- local_buffer.clear();
-
calib_file.clear();
calibration_cache.clear();
@@ -99,9 +110,9 @@ void Genesys_Device::clear()
dark_average_data.clear();
}
-ImagePipelineNodeBytesSource& Genesys_Device::get_pipeline_source()
+ImagePipelineNodeBufferedCallableSource& Genesys_Device::get_pipeline_source()
{
- return static_cast<ImagePipelineNodeBytesSource&>(pipeline.front());
+ return static_cast<ImagePipelineNodeBufferedCallableSource&>(pipeline.front());
}
bool Genesys_Device::is_head_pos_known(ScanHeadId scan_head) const
@@ -124,10 +135,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 +220,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 +238,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'
@@ -242,31 +254,47 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev)
<< " read_active: " << dev.read_active << '\n'
<< " parking: " << dev.parking << '\n'
<< " document: " << dev.document << '\n'
- << " read_buffer.size(): " << dev.read_buffer.size() << '\n'
- << " binarize_buffer.size(): " << dev.binarize_buffer.size() << '\n'
- << " local_buffer.size(): " << dev.local_buffer.size() << '\n'
- << " oe_buffer.size(): " << dev.oe_buffer.size() << '\n'
<< " total_bytes_read: " << dev.total_bytes_read << '\n'
<< " total_bytes_to_read: " << dev.total_bytes_to_read << '\n'
<< " session: " << format_indent_braced_list(4, dev.session) << '\n'
- << " lineart_lut: (not printed)\n"
<< " calibration_cache: (not printed)\n"
<< " line_count: " << dev.line_count << '\n'
<< " segment_order: "
<< format_indent_braced_list(4, format_vector_unsigned(4, dev.segment_order)) << '\n'
- << " buffer_image: " << dev.buffer_image << '\n'
- << " img_buffer.size(): " << dev.img_buffer.size() << '\n'
<< '}';
return out;
}
+void apply_reg_settings_to_device_write_only(Genesys_Device& dev,
+ const GenesysRegisterSettingSet& regs)
+{
+ GenesysRegisterSettingSet backup;
+ for (const auto& reg : regs) {
+ dev.interface->write_register(reg.address, reg.value);
+ }
+}
+
void apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs)
{
+ apply_reg_settings_to_device_with_backup(dev, regs);
+}
+
+GenesysRegisterSettingSet
+ apply_reg_settings_to_device_with_backup(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);
+ 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
diff --git a/backend/genesys/device.h b/backend/genesys/device.h
index 6c744c9..ded6a48 100644
--- a/backend/genesys/device.h
+++ b/backend/genesys/device.h
@@ -46,7 +46,6 @@
#include "calibration.h"
#include "command_set.h"
-#include "buffer.h"
#include "enums.h"
#include "image_pipeline.h"
#include "motor.h"
@@ -55,6 +54,7 @@
#include "register.h"
#include "usb_device.h"
#include "scanner_interface.h"
+#include "utilities.h"
#include <vector>
namespace genesys {
@@ -77,22 +77,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 +99,16 @@ struct MethodResolutions
return *std::min_element(resolutions_x.begin(), resolutions_x.end());
}
+ unsigned get_nearest_resolution_x(unsigned resolution) const
+ {
+ return *std::min_element(resolutions_x.begin(), resolutions_x.end(),
+ [&](unsigned lhs, unsigned rhs)
+ {
+ return std::abs(static_cast<int>(lhs) - static_cast<int>(resolution)) <
+ std::abs(static_cast<int>(rhs) - static_cast<int>(resolution));
+ });
+ }
+
unsigned get_min_resolution_y() const
{
return *std::min_element(resolutions_y.begin(), resolutions_y.end());
@@ -143,51 +146,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 +229,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 +264,8 @@ struct Genesys_Device
// frees commonly used data
void clear();
- SANE_Word vendorId = 0; /**< USB vendor identifier */
- SANE_Word productId = 0; /**< USB product identifier */
+ std::uint16_t vendorId = 0; // USB vendor identifier
+ std::uint16_t productId = 0; // USB product identifier
// USB mode:
// 0: not set
@@ -261,42 +282,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];
@@ -313,13 +317,6 @@ struct Genesys_Device
// for sheetfed scanner's, is TRUE when there is a document in the scanner
bool document = false;
- Genesys_Buffer read_buffer;
-
- // buffer for digital lineart from gray data
- Genesys_Buffer binarize_buffer;
- // local buffer for gray data during dynamix lineart
- Genesys_Buffer local_buffer;
-
// total bytes read sent to frontend
size_t total_bytes_read = 0;
// total bytes read to be sent to frontend
@@ -328,9 +325,6 @@ struct Genesys_Device
// contains computed data for the current setup
ScanSession session;
- // look up table used in dynamic rasterization
- unsigned char lineart_lut[256] = {};
-
Calibration calibration_cache;
// number of scan lines used during scan
@@ -339,28 +333,19 @@ struct Genesys_Device
// array describing the order of the sub-segments of the sensor
std::vector<unsigned> segment_order;
- // buffer to handle even/odd data
- Genesys_Buffer oe_buffer = {};
-
// stores information about how the input image should be processed
ImagePipelineStack pipeline;
// an buffer that allows reading from `pipeline` in chunks of any size
ImageBuffer pipeline_buffer;
- // when true the scanned picture is first buffered to allow software image enhancements
- bool buffer_image = false;
-
- // image buffer where the scanned picture is stored
- std::vector<std::uint8_t> img_buffer;
-
- ImagePipelineNodeBytesSource& get_pipeline_source();
+ ImagePipelineNodeBufferedCallableSource& get_pipeline_source();
std::unique_ptr<ScannerInterface> interface;
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 +367,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
diff --git a/backend/genesys/enums.cpp b/backend/genesys/enums.cpp
index f515cfd..cd4be7d 100644
--- a/backend/genesys/enums.cpp
+++ b/backend/genesys/enums.cpp
@@ -109,6 +109,248 @@ 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_90: out << "CANON_LIDE_90"; break;
+ case ModelId::CANON_LIDE_100: out << "CANON_LIDE_100"; break;
+ case ModelId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
+ case ModelId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;
+ case ModelId::CANON_LIDE_200: out << "CANON_LIDE_200"; break;
+ case ModelId::CANON_LIDE_210: out << "CANON_LIDE_210"; break;
+ case ModelId::CANON_LIDE_220: out << "CANON_LIDE_220"; break;
+ case ModelId::CANON_LIDE_700F: out << "CANON_LIDE_700F"; break;
+ case ModelId::DCT_DOCKETPORT_487: out << "DCT_DOCKETPORT_487"; break;
+ case ModelId::HP_SCANJET_2300C: out << "HP_SCANJET_2300C"; break;
+ case ModelId::HP_SCANJET_2400C: out << "HP_SCANJET_2400C"; break;
+ case ModelId::HP_SCANJET_3670: out << "HP_SCANJET_3670"; break;
+ case ModelId::HP_SCANJET_4850C: out << "HP_SCANJET_4850C"; break;
+ case ModelId::HP_SCANJET_G4010: out << "HP_SCANJET_G4010"; break;
+ case ModelId::HP_SCANJET_G4050: out << "HP_SCANJET_G4050"; break;
+ case ModelId::HP_SCANJET_N6310: out << "HP_SCANJET_N6310"; break;
+ case ModelId::MEDION_MD5345: out << "MEDION_MD5345"; break;
+ case ModelId::PANASONIC_KV_SS080: out << "PANASONIC_KV_SS080"; break;
+ case ModelId::PENTAX_DSMOBILE_600: out << "PENTAX_DSMOBILE_600"; break;
+ case ModelId::PLUSTEK_OPTICBOOK_3800: out << "PLUSTEK_OPTICBOOK_3800"; break;
+ case ModelId::PLUSTEK_OPTICFILM_7200: out << "PLUSTEK_OPTICFILM_7200"; break;
+ case ModelId::PLUSTEK_OPTICFILM_7200I: out << "PLUSTEK_OPTICFILM_7200I"; break;
+ case ModelId::PLUSTEK_OPTICFILM_7300: out << "PLUSTEK_OPTICFILM_7300"; break;
+ case ModelId::PLUSTEK_OPTICFILM_7400: out << "PLUSTEK_OPTICFILM_7400"; break;
+ case ModelId::PLUSTEK_OPTICFILM_7500I: out << "PLUSTEK_OPTICFILM_7500I"; break;
+ case ModelId::PLUSTEK_OPTICFILM_8200I: out << "PLUSTEK_OPTICFILM_8200I"; break;
+ case ModelId::PLUSTEK_OPTICPRO_3600: out << "PLUSTEK_OPTICPRO_3600"; break;
+ case ModelId::PLUSTEK_OPTICPRO_ST12: out << "PLUSTEK_OPTICPRO_ST12"; break;
+ case ModelId::PLUSTEK_OPTICPRO_ST24: out << "PLUSTEK_OPTICPRO_ST24"; break;
+ case ModelId::SYSCAN_DOCKETPORT_465: out << "SYSCAN_DOCKETPORT_465"; break;
+ case ModelId::SYSCAN_DOCKETPORT_467: out << "SYSCAN_DOCKETPORT_467"; break;
+ case ModelId::SYSCAN_DOCKETPORT_485: out << "SYSCAN_DOCKETPORT_485"; break;
+ case ModelId::SYSCAN_DOCKETPORT_665: out << "SYSCAN_DOCKETPORT_665"; break;
+ case ModelId::SYSCAN_DOCKETPORT_685: out << "SYSCAN_DOCKETPORT_685"; break;
+ case ModelId::UMAX_ASTRA_4500: out << "UMAX_ASTRA_4500"; break;
+ case ModelId::VISIONEER_7100: out << "VISIONEER_7100"; break;
+ case ModelId::VISIONEER_ROADWARRIOR: out << "VISIONEER_ROADWARRIOR"; break;
+ case ModelId::VISIONEER_STROBE_XP100_REVISION3:
+ out << "VISIONEER_STROBE_XP100_REVISION3"; break;
+ case ModelId::VISIONEER_STROBE_XP200: out << "VISIONEER_STROBE_XP200"; break;
+ case ModelId::VISIONEER_STROBE_XP300: out << "VISIONEER_STROBE_XP300"; break;
+ case ModelId::XEROX_2400: out << "XEROX_2400"; break;
+ case ModelId::XEROX_TRAVELSCANNER_100: out << "XEROX_TRAVELSCANNER_100"; break;
+ default:
+ out << static_cast<unsigned>(id); break;
+ }
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, SensorId id)
+{
+ switch (id) {
+ case SensorId::CCD_5345: out << "CCD_5345"; break;
+ case SensorId::CCD_CANON_4400F: out << "CCD_CANON_4400F"; break;
+ case SensorId::CCD_CANON_5600F: out << "CCD_CANON_5600F"; break;
+ case SensorId::CCD_CANON_8400F: out << "CCD_CANON_8400F"; break;
+ case SensorId::CCD_CANON_8600F: out << "CCD_CANON_8600F"; break;
+ case SensorId::CCD_DP665: out << "CCD_DP665"; break;
+ case SensorId::CCD_DP685: out << "CCD_DP685"; break;
+ case SensorId::CCD_DSMOBILE600: out << "CCD_DSMOBILE600"; break;
+ case SensorId::CCD_DOCKETPORT_487: out << "CCD_DOCKETPORT_487"; break;
+ case SensorId::CCD_G4050: out << "CCD_G4050"; break;
+ case SensorId::CCD_HP2300: out << "CCD_HP2300"; break;
+ case SensorId::CCD_HP2400: out << "CCD_HP2400"; break;
+ case SensorId::CCD_HP3670: out << "CCD_HP3670"; break;
+ case SensorId::CCD_HP_N6310: out << "CCD_HP_N6310"; break;
+ case SensorId::CCD_HP_4850C: out << "CCD_HP_4850C"; break;
+ case SensorId::CCD_IMG101: out << "CCD_IMG101"; break;
+ case SensorId::CCD_KVSS080: out << "CCD_KVSS080"; break;
+ case SensorId::CCD_PLUSTEK_OPTICBOOK_3800: out << "CCD_PLUSTEK_OPTICBOOK_3800"; break;
+ case SensorId::CCD_PLUSTEK_OPTICFILM_7200: out << "CCD_PLUSTEK_OPTICFILM_7200"; break;
+ case SensorId::CCD_PLUSTEK_OPTICFILM_7200I: out << "CCD_PLUSTEK_OPTICFILM_7200I"; break;
+ case SensorId::CCD_PLUSTEK_OPTICFILM_7300: out << "CCD_PLUSTEK_OPTICFILM_7300"; break;
+ case SensorId::CCD_PLUSTEK_OPTICFILM_7400: out << "CCD_PLUSTEK_OPTICFILM_7400"; break;
+ case SensorId::CCD_PLUSTEK_OPTICFILM_7500I: out << "CCD_PLUSTEK_OPTICFILM_7500I"; break;
+ case SensorId::CCD_PLUSTEK_OPTICFILM_8200I: out << "CCD_PLUSTEK_OPTICFILM_8200I"; break;
+ case SensorId::CCD_PLUSTEK_OPTICPRO_3600: out << "CCD_PLUSTEK_OPTICPRO_3600"; break;
+ case SensorId::CCD_ROADWARRIOR: out << "CCD_ROADWARRIOR"; break;
+ case SensorId::CCD_ST12: out << "CCD_ST12"; break;
+ case SensorId::CCD_ST24: out << "CCD_ST24"; break;
+ case SensorId::CCD_UMAX: out << "CCD_UMAX"; break;
+ case SensorId::CCD_XP300: out << "CCD_XP300"; break;
+ case SensorId::CIS_CANON_LIDE_35: out << "CIS_CANON_LIDE_35"; break;
+ case SensorId::CIS_CANON_LIDE_60: out << "CIS_CANON_LIDE_60"; break;
+ case SensorId::CIS_CANON_LIDE_80: out << "CIS_CANON_LIDE_80"; break;
+ case SensorId::CIS_CANON_LIDE_90: out << "CIS_CANON_LIDE_90"; break;
+ case SensorId::CIS_CANON_LIDE_100: out << "CIS_CANON_LIDE_100"; break;
+ case SensorId::CIS_CANON_LIDE_110: out << "CIS_CANON_LIDE_110"; break;
+ case SensorId::CIS_CANON_LIDE_120: out << "CIS_CANON_LIDE_120"; break;
+ case SensorId::CIS_CANON_LIDE_200: out << "CIS_CANON_LIDE_200"; break;
+ case SensorId::CIS_CANON_LIDE_210: out << "CIS_CANON_LIDE_210"; break;
+ case SensorId::CIS_CANON_LIDE_220: out << "CIS_CANON_LIDE_220"; break;
+ case SensorId::CIS_CANON_LIDE_700F: out << "CIS_CANON_LIDE_700F"; break;
+ case SensorId::CIS_XP200: out << "CIS_XP200"; break;
+ default:
+ out << static_cast<unsigned>(id); break;
+ }
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, AdcId id)
+{
+ switch (id) {
+ case AdcId::UNKNOWN: out << "UNKNOWN"; break;
+ case AdcId::AD_XP200: out << "AD_XP200"; break;
+ case AdcId::CANON_LIDE_35: out << "CANON_LIDE_35"; break;
+ case AdcId::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
+ case AdcId::CANON_LIDE_90: out << "CANON_LIDE_90"; break;
+ case AdcId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
+ case AdcId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;
+ case AdcId::CANON_LIDE_200: out << "CANON_LIDE_200"; break;
+ case AdcId::CANON_LIDE_700F: out << "CANON_LIDE_700F"; break;
+ case AdcId::CANON_4400F: out << "CANON_4400F"; break;
+ case AdcId::CANON_5600F: out << "CANON_5600F"; break;
+ case AdcId::CANON_8400F: out << "CANON_8400F"; break;
+ case AdcId::CANON_8600F: out << "CANON_8600F"; break;
+ case AdcId::G4050: out << "G4050"; break;
+ case AdcId::IMG101: out << "IMG101"; break;
+ case AdcId::KVSS080: out << "KVSS080"; break;
+ case AdcId::PLUSTEK_OPTICBOOK_3800: out << "PLUSTEK_OPTICBOOK_3800"; break;
+ case AdcId::PLUSTEK_OPTICFILM_7200: out << "PLUSTEK_OPTICFILM_7200"; break;
+ case AdcId::PLUSTEK_OPTICFILM_7200I: out << "PLUSTEK_OPTICFILM_7200I"; break;
+ case AdcId::PLUSTEK_OPTICFILM_7300: out << "PLUSTEK_OPTICFILM_7300"; break;
+ case AdcId::PLUSTEK_OPTICFILM_7400: out << "PLUSTEK_OPTICFILM_7400"; break;
+ case AdcId::PLUSTEK_OPTICFILM_7500I: out << "PLUSTEK_OPTICFILM_7500I"; break;
+ case AdcId::PLUSTEK_OPTICFILM_8200I: out << "PLUSTEK_OPTICFILM_8200I"; break;
+ case AdcId::PLUSTEK_OPTICPRO_3600: out << "PLUSTEK_OPTICPRO_3600"; break;
+ case AdcId::WOLFSON_5345: out << "WOLFSON_5345"; break;
+ case AdcId::WOLFSON_DSM600: out << "WOLFSON_DSM600"; break;
+ case AdcId::WOLFSON_HP2300: out << "WOLFSON_HP2300"; break;
+ case AdcId::WOLFSON_HP2400: out << "WOLFSON_HP2400"; break;
+ case AdcId::WOLFSON_HP3670: out << "WOLFSON_HP3670"; break;
+ case AdcId::WOLFSON_ST12: out << "WOLFSON_ST12"; break;
+ case AdcId::WOLFSON_ST24: out << "WOLFSON_ST24"; break;
+ case AdcId::WOLFSON_UMAX: out << "WOLFSON_UMAX"; break;
+ case AdcId::WOLFSON_XP300: out << "WOLFSON_XP300"; break;
+ default:
+ out << static_cast<unsigned>(id); break;
+ }
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, GpioId id)
+{
+ switch (id) {
+ case GpioId::UNKNOWN: out << "UNKNOWN"; break;
+ case GpioId::CANON_LIDE_35: out << "CANON_LIDE_35"; break;
+ case GpioId::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
+ case GpioId::CANON_LIDE_90: out << "CANON_LIDE_90"; break;
+ case GpioId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
+ case GpioId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;
+ case GpioId::CANON_LIDE_200: out << "CANON_LIDE_200"; break;
+ case GpioId::CANON_LIDE_210: out << "CANON_LIDE_210"; break;
+ case GpioId::CANON_LIDE_700F: out << "CANON_LIDE_700F"; break;
+ case GpioId::CANON_4400F: out << "CANON_4400F"; break;
+ case GpioId::CANON_5600F: out << "CANON_5600F"; break;
+ case GpioId::CANON_8400F: out << "CANON_8400F"; break;
+ case GpioId::CANON_8600F: out << "CANON_8600F"; break;
+ case GpioId::DP665: out << "DP665"; break;
+ case GpioId::DP685: out << "DP685"; break;
+ case GpioId::G4050: out << "G4050"; break;
+ case GpioId::HP2300: out << "HP2300"; break;
+ case GpioId::HP2400: out << "HP2400"; break;
+ case GpioId::HP3670: out << "HP3670"; break;
+ case GpioId::HP_N6310: out << "HP_N6310"; break;
+ case GpioId::IMG101: out << "IMG101"; break;
+ case GpioId::KVSS080: out << "KVSS080"; break;
+ case GpioId::MD_5345: out << "MD_5345"; break;
+ case GpioId::PLUSTEK_OPTICBOOK_3800: out << "PLUSTEK_OPTICBOOK_3800"; break;
+ case GpioId::PLUSTEK_OPTICFILM_7200I: out << "PLUSTEK_OPTICFILM_7200I"; break;
+ case GpioId::PLUSTEK_OPTICFILM_7300: out << "PLUSTEK_OPTICFILM_7300"; break;
+ case GpioId::PLUSTEK_OPTICFILM_7400: out << "PLUSTEK_OPTICFILM_7400"; break;
+ case GpioId::PLUSTEK_OPTICFILM_7500I: out << "PLUSTEK_OPTICFILM_7500I"; break;
+ case GpioId::PLUSTEK_OPTICFILM_8200I: out << "PLUSTEK_OPTICFILM_8200I"; break;
+ case GpioId::PLUSTEK_OPTICPRO_3600: out << "PLUSTEK_OPTICPRO_3600"; break;
+ case GpioId::ST12: out << "ST12"; break;
+ case GpioId::ST24: out << "ST24"; break;
+ case GpioId::UMAX: out << "UMAX"; break;
+ case GpioId::XP200: out << "XP200"; break;
+ case GpioId::XP300: out << "XP300"; break;
+ default: out << static_cast<unsigned>(id); break;
+ }
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, MotorId id)
+{
+ switch (id) {
+ case MotorId::UNKNOWN: out << "UNKNOWN"; break;
+ case MotorId::CANON_LIDE_90: out << "CANON_LIDE_90"; break;
+ case MotorId::CANON_LIDE_100: out << "CANON_LIDE_100"; break;
+ case MotorId::CANON_LIDE_110: out << "CANON_LIDE_110"; break;
+ case MotorId::CANON_LIDE_120: out << "CANON_LIDE_120"; break;
+ case MotorId::CANON_LIDE_200: out << "CANON_LIDE_200"; break;
+ case MotorId::CANON_LIDE_210: out << "CANON_LIDE_210"; break;
+ case MotorId::CANON_LIDE_35: out << "CANON_LIDE_35"; break;
+ case MotorId::CANON_LIDE_60: out << "CANON_LIDE_60"; break;
+ case MotorId::CANON_LIDE_700: out << "CANON_LIDE_700"; break;
+ case MotorId::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
+ case MotorId::CANON_4400F: out << "CANON_4400F"; break;
+ case MotorId::CANON_5600F: out << "CANON_5600F"; break;
+ case MotorId::CANON_8400F: out << "CANON_8400F"; break;
+ case MotorId::CANON_8600F: out << "CANON_8600F"; break;
+ case MotorId::DP665: out << "DP665"; break;
+ case MotorId::DSMOBILE_600: out << "DSMOBILE_600"; break;
+ case MotorId::G4050: out << "G4050"; break;
+ case MotorId::HP2300: out << "HP2300"; break;
+ case MotorId::HP2400: out << "HP2400"; break;
+ case MotorId::HP3670: out << "HP3670"; break;
+ case MotorId::IMG101: out << "IMG101"; break;
+ case MotorId::KVSS080: out << "KVSS080"; break;
+ case MotorId::MD_5345: out << "MD_5345"; break;
+ case MotorId::PLUSTEK_OPTICBOOK_3800: out << "PLUSTEK_OPTICBOOK_3800"; break;
+ case MotorId::PLUSTEK_OPTICFILM_7200: out << "PLUSTEK_OPTICFILM_7200"; break;
+ case MotorId::PLUSTEK_OPTICFILM_7200I: out << "PLUSTEK_OPTICFILM_7200I"; break;
+ case MotorId::PLUSTEK_OPTICFILM_7300: out << "PLUSTEK_OPTICFILM_7300"; break;
+ case MotorId::PLUSTEK_OPTICFILM_7400: out << "PLUSTEK_OPTICFILM_7400"; break;
+ case MotorId::PLUSTEK_OPTICFILM_7500I: out << "PLUSTEK_OPTICFILM_7500I"; break;
+ case MotorId::PLUSTEK_OPTICFILM_8200I: out << "PLUSTEK_OPTICFILM_8200I"; break;
+ case MotorId::PLUSTEK_OPTICPRO_3600: out << "PLUSTEK_OPTICPRO_3600"; break;
+ case MotorId::ROADWARRIOR: out << "ROADWARRIOR"; break;
+ case MotorId::ST24: out << "ST24"; break;
+ case MotorId::UMAX: out << "UMAX"; break;
+ case MotorId::XP200: out << "XP200"; break;
+ case MotorId::XP300: out << "XP300"; break;
+ default: out << static_cast<unsigned>(id); break;
+ }
+ return out;
+}
+
std::ostream& operator<<(std::ostream& out, StepType type)
{
switch (type) {
diff --git a/backend/genesys/enums.h b/backend/genesys/enums.h
index 810c4ca..0e16ba4 100644
--- a/backend/genesys/enums.h
+++ b/backend/genesys/enums.h
@@ -182,6 +182,7 @@ enum class ModelId : unsigned
CANON_LIDE_50,
CANON_LIDE_60,
CANON_LIDE_80,
+ CANON_LIDE_90,
CANON_LIDE_100,
CANON_LIDE_110,
CANON_LIDE_120,
@@ -201,9 +202,12 @@ enum class ModelId : unsigned
PANASONIC_KV_SS080,
PENTAX_DSMOBILE_600,
PLUSTEK_OPTICBOOK_3800,
+ PLUSTEK_OPTICFILM_7200,
PLUSTEK_OPTICFILM_7200I,
PLUSTEK_OPTICFILM_7300,
+ PLUSTEK_OPTICFILM_7400,
PLUSTEK_OPTICFILM_7500I,
+ PLUSTEK_OPTICFILM_8200I,
PLUSTEK_OPTICPRO_3600,
PLUSTEK_OPTICPRO_ST12,
PLUSTEK_OPTICPRO_ST24,
@@ -222,16 +226,33 @@ enum class ModelId : unsigned
XEROX_TRAVELSCANNER_100,
};
+inline void serialize(std::istream& str, ModelId& x)
+{
+ unsigned value;
+ serialize(str, value);
+ x = static_cast<ModelId>(value);
+}
+
+inline void serialize(std::ostream& str, ModelId& x)
+{
+ unsigned value = static_cast<unsigned>(x);
+ serialize(str, value);
+}
+
+std::ostream& operator<<(std::ostream& out, ModelId id);
+
enum class SensorId : unsigned
{
UNKNOWN = 0,
CCD_5345,
CCD_CANON_4400F,
+ CCD_CANON_5600F,
CCD_CANON_8400F,
CCD_CANON_8600F,
CCD_DP665,
CCD_DP685,
CCD_DSMOBILE600,
+ CCD_DOCKETPORT_487,
CCD_G4050,
CCD_HP2300,
CCD_HP2400,
@@ -241,9 +262,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,7 +275,9 @@ enum class SensorId : unsigned
CCD_UMAX,
CCD_XP300,
CIS_CANON_LIDE_35,
+ CIS_CANON_LIDE_60,
CIS_CANON_LIDE_80,
+ CIS_CANON_LIDE_90,
CIS_CANON_LIDE_100,
CIS_CANON_LIDE_110,
CIS_CANON_LIDE_120,
@@ -275,6 +301,8 @@ inline void serialize(std::ostream& str, SensorId& x)
serialize(str, value);
}
+std::ostream& operator<<(std::ostream& out, SensorId id);
+
enum class AdcId : unsigned
{
@@ -282,20 +310,25 @@ enum class AdcId : unsigned
AD_XP200,
CANON_LIDE_35,
CANON_LIDE_80,
+ CANON_LIDE_90,
CANON_LIDE_110,
CANON_LIDE_120,
CANON_LIDE_200,
CANON_LIDE_700F,
CANON_4400F,
+ CANON_5600F,
CANON_8400F,
CANON_8600F,
G4050,
IMG101,
KVSS080,
PLUSTEK_OPTICBOOK_3800,
+ PLUSTEK_OPTICFILM_7200,
PLUSTEK_OPTICFILM_7200I,
PLUSTEK_OPTICFILM_7300,
+ PLUSTEK_OPTICFILM_7400,
PLUSTEK_OPTICFILM_7500I,
+ PLUSTEK_OPTICFILM_8200I,
PLUSTEK_OPTICPRO_3600,
WOLFSON_5345,
WOLFSON_DSM600,
@@ -321,17 +354,21 @@ 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,
CANON_LIDE_35,
CANON_LIDE_80,
+ CANON_LIDE_90,
CANON_LIDE_110,
CANON_LIDE_120,
CANON_LIDE_200,
CANON_LIDE_210,
CANON_LIDE_700F,
CANON_4400F,
+ CANON_5600F,
CANON_8400F,
CANON_8600F,
DP665,
@@ -345,9 +382,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 +396,8 @@ enum class GpioId : unsigned
XP300,
};
+std::ostream& operator<<(std::ostream& out, GpioId id);
+
enum class MotorId : unsigned
{
UNKNOWN = 0,
@@ -365,9 +407,12 @@ enum class MotorId : unsigned
CANON_LIDE_200,
CANON_LIDE_210,
CANON_LIDE_35,
+ CANON_LIDE_60,
CANON_LIDE_700,
CANON_LIDE_80,
+ CANON_LIDE_90,
CANON_4400F,
+ CANON_5600F,
CANON_8400F,
CANON_8600F,
DP665,
@@ -380,9 +425,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 +439,8 @@ enum class MotorId : unsigned
XP300,
};
+std::ostream& operator<<(std::ostream& out, MotorId id);
+
enum class StepType : unsigned
{
FULL = 0,
@@ -423,6 +473,7 @@ enum class AsicType : unsigned
UNKNOWN = 0,
GL646,
GL841,
+ GL842,
GL843,
GL845,
GL846,
@@ -431,6 +482,92 @@ 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,
+
+ // host-side calibration uses a complete scan
+ HOST_SIDE_CALIBRATION_COMPLETE_SCAN = 1 << 9,
+
+ // whether scanner must wait for the head while parking
+ MUST_WAIT = 1 << 10,
+
+ // use zeroes for dark calibration
+ USE_CONSTANT_FOR_DARK_CALIBRATION = 1 << 11,
+
+ // do dark and white calibration in one run
+ DARK_WHITE_CALIBRATION = 1 << 12,
+
+ // allow custom gamma tables
+ CUSTOM_GAMMA = 1 << 13,
+
+ // disable fast feeding mode on this scanner
+ DISABLE_FAST_FEEDING = 1 << 14,
+
+ // the scanner uses multi-segment sensors that must be handled during calibration
+ SIS_SENSOR = 1 << 16,
+
+ // the head must be reparked between shading scans
+ SHADING_REPARK = 1 << 18,
+
+ // the scanner 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 +575,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 +632,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
diff --git a/backend/genesys/error.cpp b/backend/genesys/error.cpp
index 6c921c1..46d79c9 100644
--- a/backend/genesys/error.cpp
+++ b/backend/genesys/error.cpp
@@ -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
diff --git a/backend/genesys/error.h b/backend/genesys/error.h
index 5aba8cf..26235dd 100644
--- a/backend/genesys/error.h
+++ b/backend/genesys/error.h
@@ -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)
{
@@ -172,6 +173,27 @@ SANE_Status wrap_exceptions_to_status_code(const char* func, F&& function)
}
template<class F>
+SANE_Status wrap_exceptions_to_status_code_return(const char* func, F&& function)
+{
+ try {
+ return function();
+ } catch (const SaneException& exc) {
+ DBG(DBG_error, "%s: got error: %s\n", func, exc.what());
+ return exc.status();
+ } catch (const std::bad_alloc& exc) {
+ (void) exc;
+ DBG(DBG_error, "%s: failed to allocate memory\n", func);
+ return SANE_STATUS_NO_MEM;
+ } catch (const std::exception& exc) {
+ DBG(DBG_error, "%s: got uncaught exception: %s\n", func, exc.what());
+ return SANE_STATUS_INVAL;
+ } catch (...) {
+ DBG(DBG_error, "%s: got unknown uncaught exception\n", func);
+ return SANE_STATUS_INVAL;
+ }
+}
+
+template<class F>
void catch_all_exceptions(const char* func, F&& function)
{
try {
diff --git a/backend/genesys/fwd.h b/backend/genesys/fwd.h
index 2d55f98..ea335f7 100644
--- a/backend/genesys/fwd.h
+++ b/backend/genesys/fwd.h
@@ -46,9 +46,6 @@
namespace genesys {
-// buffer.h
-struct Genesys_Buffer;
-
// calibration.h
struct Genesys_Calibration_Cache;
@@ -56,7 +53,6 @@ struct Genesys_Calibration_Cache;
class CommandSet;
// device.h
-class FixedFloat;
struct Genesys_Gpo;
struct MethodResolutions;
struct Genesys_Model;
@@ -75,8 +71,6 @@ class Image;
// image_buffer.h
class ImageBuffer;
-class FakeBufferModel;
-class ImageBufferGenesysUsb;
// image_pipeline.h
class ImagePipelineNode;
@@ -88,12 +82,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 +107,6 @@ class ScannerInterfaceUsb;
class TestScannerInterface;
// sensor.h
-class ResolutionFilter;
struct GenesysFrontendLayout;
struct Genesys_Frontend;
struct SensorExposure;
@@ -124,6 +117,10 @@ struct Genesys_Settings;
struct SetupParams;
struct ScanSession;
+// value_filter.h
+template<class T> class ValueFilter;
+template<class T> class ValueFilterAny;
+
// test_usb_device.h
class TestUsbDevice;
diff --git a/backend/genesys/genesys.cpp b/backend/genesys/genesys.cpp
index 7c25168..9d80cfa 100644
--- a/backend/genesys/genesys.cpp
+++ b/backend/genesys/genesys.cpp
@@ -61,9 +61,9 @@
#define DEBUG_NOT_STATIC
#include "genesys.h"
-#include "conv.h"
#include "gl124_registers.h"
#include "gl841_registers.h"
+#include "gl842_registers.h"
#include "gl843_registers.h"
#include "gl846_registers.h"
#include "gl847_registers.h"
@@ -73,7 +73,6 @@
#include "test_scanner_interface.h"
#include "test_settings.h"
#include "../include/sane/sanei_config.h"
-#include "../include/sane/sanei_magic.h"
#include <array>
#include <cmath>
@@ -111,8 +110,8 @@ namespace {
static SANE_String_Const mode_list[] = {
SANE_VALUE_SCAN_MODE_COLOR,
SANE_VALUE_SCAN_MODE_GRAY,
- /* SANE_TITLE_HALFTONE, currently unused */
- SANE_VALUE_SCAN_MODE_LINEART,
+ // SANE_TITLE_HALFTONE, not used
+ // SANE_VALUE_SCAN_MODE_LINEART, not used
nullptr
};
@@ -131,12 +130,6 @@ static SANE_String_Const cis_color_filter_list[] = {
nullptr
};
-static SANE_Range swdespeck_range = {
- 1,
- 9,
- 1
-};
-
static SANE_Range time_range = {
0, /* minimum */
60, /* maximum */
@@ -162,15 +155,9 @@ static const SANE_Range u16_range = {
};
static const SANE_Range percentage_range = {
- SANE_FIX (0), /* minimum */
- SANE_FIX (100), /* maximum */
- SANE_FIX (1) /* quantization */
-};
-
-static const SANE_Range threshold_curve_range = {
- 0, /* minimum */
- 127, /* maximum */
- 1 /* quantization */
+ float_to_fixed(0), // minimum
+ float_to_fixed(100), // maximum
+ float_to_fixed(1) // quantization
};
/**
@@ -191,7 +178,7 @@ static const SANE_Range expiration_range = {
1 /* quantization */
};
-const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev)
+const Genesys_Sensor& sanei_genesys_find_sensor_any(const Genesys_Device* dev)
{
DBG_HELPER(dbg);
for (const auto& sensor : *s_sensors) {
@@ -202,7 +189,7 @@ const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev)
throw std::runtime_error("Given device does not have sensor defined");
}
-Genesys_Sensor* find_sensor_impl(Genesys_Device* dev, unsigned dpi, unsigned channels,
+Genesys_Sensor* find_sensor_impl(const Genesys_Device* dev, unsigned dpi, unsigned channels,
ScanMethod scan_method)
{
DBG_HELPER_ARGS(dbg, "dpi: %d, channels: %d, scan_method: %d", dpi, channels,
@@ -217,7 +204,7 @@ Genesys_Sensor* find_sensor_impl(Genesys_Device* dev, unsigned dpi, unsigned cha
return nullptr;
}
-bool sanei_genesys_has_sensor(Genesys_Device* dev, unsigned dpi, unsigned channels,
+bool sanei_genesys_has_sensor(const Genesys_Device* dev, unsigned dpi, unsigned channels,
ScanMethod scan_method)
{
DBG_HELPER_ARGS(dbg, "dpi: %d, channels: %d, scan_method: %d", dpi, channels,
@@ -225,8 +212,8 @@ bool sanei_genesys_has_sensor(Genesys_Device* dev, unsigned dpi, unsigned channe
return find_sensor_impl(dev, dpi, channels, scan_method) != nullptr;
}
-const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, unsigned dpi, unsigned channels,
- ScanMethod scan_method)
+const Genesys_Sensor& sanei_genesys_find_sensor(const Genesys_Device* dev, unsigned dpi,
+ unsigned channels, ScanMethod scan_method)
{
DBG_HELPER_ARGS(dbg, "dpi: %d, channels: %d, scan_method: %d", dpi, channels,
static_cast<unsigned>(scan_method));
@@ -250,12 +237,14 @@ Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, unsigne
std::vector<std::reference_wrapper<const Genesys_Sensor>>
- sanei_genesys_find_sensors_all(Genesys_Device* dev, ScanMethod scan_method)
+ sanei_genesys_find_sensors_all(const Genesys_Device* dev, ScanMethod scan_method)
{
DBG_HELPER_ARGS(dbg, "scan_method: %d", static_cast<unsigned>(scan_method));
std::vector<std::reference_wrapper<const Genesys_Sensor>> ret;
- for (const Genesys_Sensor& sensor : sanei_genesys_find_sensors_all_for_write(dev, scan_method)) {
- ret.push_back(sensor);
+ for (auto& sensor : *s_sensors) {
+ if (dev->model->sensor_id == sensor.sensor_id && sensor.method == scan_method) {
+ ret.push_back(sensor);
+ }
}
return ret;
}
@@ -308,6 +297,24 @@ void sanei_genesys_init_structs (Genesys_Device * dev)
}
}
+ if (dev->model->asic_type == AsicType::GL845 ||
+ dev->model->asic_type == AsicType::GL846 ||
+ dev->model->asic_type == AsicType::GL847 ||
+ dev->model->asic_type == AsicType::GL124)
+ {
+ bool memory_layout_found = false;
+ for (const auto& memory_layout : *s_memory_layout) {
+ if (memory_layout.models.matches(dev->model->model_id)) {
+ dev->memory_layout = memory_layout;
+ memory_layout_found = true;
+ break;
+ }
+ }
+ if (!memory_layout_found) {
+ throw SaneException("Could not find memory layout");
+ }
+ }
+
if (!motor_ok || !gpo_ok || !fe_ok) {
throw SaneException("bad description(s) for fe/gpo/motor=%d/%d/%d\n",
static_cast<unsigned>(dev->model->sensor_id),
@@ -316,33 +323,6 @@ void sanei_genesys_init_structs (Genesys_Device * dev)
}
}
-/* Generate slope table for motor movement */
-/**
- * This function generates a slope table using the slope from the motor struct
- * truncated at the given exposure time or step count, whichever comes first.
- * The summed time of the acceleration steps is returned, and the
- * number of accerelation steps is put into used_steps.
- *
- * @param dev Device struct
- * @param slope_table Table to write to
- * @param step_type Generate table for this step_type. 0=>full, 1=>half,
- * 2=>quarter
- * @param exposure_time Minimum exposure time of a scan line
- * @param yres Resolution of a scan line
- * @param used_steps Final number of steps is stored here
- * @return Motor slope table
- * @note all times in pixel time
- */
-MotorSlopeTable sanei_genesys_create_slope_table3(AsicType asic_type, const Genesys_Motor& motor,
- StepType step_type, int exposure_time,
- unsigned yres)
-{
- unsigned target_speed_w = (exposure_time * yres) / motor.base_ydpi;
-
- return create_slope_table(motor.get_slope(step_type), target_speed_w, step_type, 1, 1,
- get_slope_table_max_size(asic_type));
-}
-
/** @brief computes gamma table
* Generates a gamma table of the given length within 0 and the given
* maximum value
@@ -382,7 +362,7 @@ void sanei_genesys_create_default_gamma_table(Genesys_Device* dev,
int size = 0;
int max = 0;
if (dev->model->asic_type == AsicType::GL646) {
- if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) {
+ if (has_flag(dev->model->flags, ModelFlag::GAMMA_14BIT)) {
size = 16384;
} else {
size = 4096;
@@ -411,34 +391,30 @@ void sanei_genesys_create_default_gamma_table(Genesys_Device* dev,
Note: The enhance option of the scanners does _not_ help. It only halves
the amount of pixels transfered.
*/
-SANE_Int sanei_genesys_exposure_time2(Genesys_Device * dev, float ydpi,
- StepType step_type, int endpixel, int exposure_by_led)
+SANE_Int sanei_genesys_exposure_time2(Genesys_Device * dev, const MotorProfile& profile, float ydpi,
+ int endpixel, int exposure_by_led)
{
int exposure_by_ccd = endpixel + 32;
- unsigned max_speed_motor_w = dev->motor.get_slope(step_type).max_speed_w;
+ unsigned max_speed_motor_w = profile.slope.max_speed_w;
int exposure_by_motor = static_cast<int>((max_speed_motor_w * dev->motor.base_ydpi) / ydpi);
int exposure = exposure_by_ccd;
- if (exposure < exposure_by_motor)
- exposure = exposure_by_motor;
+ if (exposure < exposure_by_motor) {
+ exposure = exposure_by_motor;
+ }
- if (exposure < exposure_by_led && dev->model->is_cis)
- exposure = exposure_by_led;
+ if (exposure < exposure_by_led && dev->model->is_cis) {
+ exposure = exposure_by_led;
+ }
- DBG(DBG_info, "%s: ydpi=%d, step=%d, endpixel=%d led=%d => exposure=%d\n", __func__,
- static_cast<int>(ydpi), static_cast<unsigned>(step_type), endpixel,
- exposure_by_led, exposure);
- return exposure;
+ return exposure;
}
/* Sends a block of shading information to the scanner.
The data is placed at address 0x0000 for color mode, gray mode and
unconditionally for the following CCD chips: HP2300, HP2400 and HP5345
- In the other cases (lineart, halftone on ccd chips not mentioned) the
- addresses are 0x2a00 for dpihw==0, 0x5500 for dpihw==1 and 0xa800 for
- dpihw==2. //Note: why this?
The data needs to be of size "size", and in little endian byte order.
*/
@@ -446,7 +422,6 @@ static void genesys_send_offset_and_shading(Genesys_Device* dev, const Genesys_S
uint8_t* data, int size)
{
DBG_HELPER_ARGS(dbg, "(size = %d)", size);
- int dpihw;
int start_address;
/* ASIC higher than gl843 doesn't have register 2A/2B, so we route to
@@ -457,84 +432,30 @@ static void genesys_send_offset_and_shading(Genesys_Device* dev, const Genesys_S
return;
}
- /* gl646, gl84[123] case */
- dpihw = dev->reg.get8(0x05) >> 6;
-
- /* TODO invert the test so only the 2 models behaving like that are
- * tested instead of adding all the others */
- /* many scanners send coefficient for lineart/gray like in color mode */
- if ((dev->settings.scan_mode == ScanColorMode::LINEART ||
- dev->settings.scan_mode == ScanColorMode::HALFTONE)
- && dev->model->sensor_id != SensorId::CCD_PLUSTEK_OPTICBOOK_3800
- && dev->model->sensor_id != SensorId::CCD_KVSS080
- && dev->model->sensor_id != SensorId::CCD_G4050
- && dev->model->sensor_id != SensorId::CCD_HP_4850C
- && dev->model->sensor_id != SensorId::CCD_CANON_4400F
- && dev->model->sensor_id != SensorId::CCD_CANON_8400F
- && dev->model->sensor_id != SensorId::CCD_CANON_8600F
- && dev->model->sensor_id != SensorId::CCD_DSMOBILE600
- && dev->model->sensor_id != SensorId::CCD_XP300
- && dev->model->sensor_id != SensorId::CCD_DP665
- && dev->model->sensor_id != SensorId::CCD_DP685
- && dev->model->sensor_id != SensorId::CIS_CANON_LIDE_80
- && dev->model->sensor_id != SensorId::CCD_ROADWARRIOR
- && dev->model->sensor_id != SensorId::CCD_HP2300
- && dev->model->sensor_id != SensorId::CCD_HP2400
- && dev->model->sensor_id != SensorId::CCD_HP3670
- && dev->model->sensor_id != SensorId::CCD_5345) /* lineart, halftone */
- {
- if (dpihw == 0) { /* 600 dpi */
- start_address = 0x02a00;
- } else if (dpihw == 1) { /* 1200 dpi */
- start_address = 0x05500;
- } else if (dpihw == 2) { /* 2400 dpi */
- start_address = 0x0a800;
- } else { /* reserved */
- throw SaneException("unknown dpihw");
- }
- }
- else { // color
- start_address = 0x00;
- }
+ start_address = 0x00;
dev->interface->write_buffer(0x3c, start_address, data, size);
}
-// ?
void sanei_genesys_init_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
int pixels_per_line)
{
DBG_HELPER_ARGS(dbg, "pixels_per_line: %d", pixels_per_line);
- if (dev->model->flags & GENESYS_FLAG_CALIBRATION_HOST_SIDE) {
- return;
- }
-
- int channels;
- int i;
-
if (dev->cmd_set->has_send_shading_data()) {
return;
}
DBG(DBG_proc, "%s (pixels_per_line = %d)\n", __func__, pixels_per_line);
- // BUG: GRAY shouldn't probably be in the if condition below. Discovered when refactoring
- if (dev->settings.scan_mode == ScanColorMode::GRAY ||
- dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS)
- {
- channels = 3;
- } else {
- channels = 1;
- }
+ unsigned channels = dev->settings.get_channels();
// 16 bit black, 16 bit white
std::vector<uint8_t> shading_data(pixels_per_line * 4 * channels, 0);
uint8_t* shading_data_ptr = shading_data.data();
- for (i = 0; i < pixels_per_line * channels; i++)
- {
+ for (unsigned i = 0; i < pixels_per_line * channels; i++) {
*shading_data_ptr++ = 0x00; /* dark lo */
*shading_data_ptr++ = 0x00; /* dark hi */
*shading_data_ptr++ = 0x00; /* white lo */
@@ -545,184 +466,6 @@ void sanei_genesys_init_shading_data(Genesys_Device* dev, const Genesys_Sensor&
pixels_per_line * 4 * channels);
}
-
-// Find the position of the reference point: takes gray level 8 bits data and find
-// first CCD usable pixel and top of scanning area
-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)
-{
- DBG_HELPER(dbg);
- int x, y;
- int current, left, top = 0;
- int size, count;
- int level = 80; /* edge threshold level */
-
- // sanity check
- if ((width < 3) || (height < 3)) {
- throw SaneException("invalid width or height");
- }
-
- /* transformed image data */
- size = width * height;
- std::vector<uint8_t> image2(size, 0);
- std::vector<uint8_t> image(size, 0);
-
- /* laplace filter to denoise picture */
- std::memcpy(image2.data(), src_data, size);
- std::memcpy(image.data(), src_data, size); // to initialize unprocessed part of the image buffer
-
- for (y = 1; y < height - 1; y++) {
- for (x = 1; x < width - 1; x++) {
- image[y * width + x] =
- (image2[(y - 1) * width + x + 1] + 2 * image2[(y - 1) * width + x] +
- image2[(y - 1) * width + x - 1] + 2 * image2[y * width + x + 1] +
- 4 * image2[y * width + x] + 2 * image2[y * width + x - 1] +
- image2[(y + 1) * width + x + 1] + 2 * image2[(y + 1) * width + x] +
- image2[(y + 1) * width + x - 1]) / 16;
- }
- }
-
- image2 = image;
- if (DBG_LEVEL >= DBG_data)
- sanei_genesys_write_pnm_file("gl_laplace.pnm", image.data(), 8, 1, width, height);
-
- /* apply X direction sobel filter
- -1 0 1
- -2 0 2
- -1 0 1
- and finds threshold level
- */
- level = 0;
- for (y = 2; y < height - 2; y++) {
- for (x = 2; x < width - 2; x++) {
- current = image2[(y - 1) * width + x + 1] - image2[(y - 1) * width + x - 1] +
- 2 * image2[y * width + x + 1] - 2 * image2[y * width + x - 1] +
- image2[(y + 1) * width + x + 1] - image2[(y + 1) * width + x - 1];
- if (current < 0)
- current = -current;
- if (current > 255)
- current = 255;
- image[y * width + x] = current;
- if (current > level)
- level = current;
- }
- }
- if (DBG_LEVEL >= DBG_data)
- sanei_genesys_write_pnm_file("gl_xsobel.pnm", image.data(), 8, 1, width, height);
-
- /* set up detection level */
- level = level / 3;
-
- /* find left black margin first
- todo: search top before left
- we average the result of N searches */
- left = 0;
- count = 0;
- for (y = 2; y < 11; y++)
- {
- x = 8;
- while ((x < width / 2) && (image[y * width + x] < level))
- {
- image[y * width + x] = 255;
- x++;
- }
- count++;
- left += x;
- }
- if (DBG_LEVEL >= DBG_data)
- sanei_genesys_write_pnm_file("gl_detected-xsobel.pnm", image.data(), 8, 1, width, height);
- left = left / count;
-
- // turn it in CCD pixel at full sensor optical resolution
- sensor.ccd_start_xoffset = start_pixel + (left * sensor.optical_res) / dpi;
-
- /* find top edge by detecting black strip */
- /* apply Y direction sobel filter
- -1 -2 -1
- 0 0 0
- 1 2 1
- */
- level = 0;
- for (y = 2; y < height - 2; y++) {
- for (x = 2; x < width - 2; x++) {
- current = -image2[(y - 1) * width + x + 1] - 2 * image2[(y - 1) * width + x] -
- image2[(y - 1) * width + x - 1] + image2[(y + 1) * width + x + 1] +
- 2 * image2[(y + 1) * width + x] + image2[(y + 1) * width + x - 1];
- if (current < 0)
- current = -current;
- if (current > 255)
- current = 255;
- image[y * width + x] = current;
- if (current > level)
- level = current;
- }
- }
- if (DBG_LEVEL >= DBG_data)
- sanei_genesys_write_pnm_file("gl_ysobel.pnm", image.data(), 8, 1, width, height);
-
- /* set up detection level */
- level = level / 3;
-
- /* search top of horizontal black stripe : TODO yet another flag */
- if (dev->model->sensor_id == SensorId::CCD_5345
- && dev->model->motor_id == MotorId::MD_5345)
- {
- top = 0;
- count = 0;
- for (x = width / 2; x < width - 1; x++)
- {
- y = 2;
- while ((y < height) && (image[x + y * width] < level))
- {
- image[y * width + x] = 255;
- y++;
- }
- count++;
- top += y;
- }
- if (DBG_LEVEL >= DBG_data)
- sanei_genesys_write_pnm_file("gl_detected-ysobel.pnm", image.data(), 8, 1, width, height);
- top = top / count;
-
- /* bottom of black stripe is of fixed witdh, this hardcoded value
- * will be moved into device struct if more such values are needed */
- top += 10;
- dev->model->y_offset_calib_white = (top * MM_PER_INCH) / dpi;
- DBG(DBG_info, "%s: black stripe y_offset = %f mm \n", __func__,
- dev->model->y_offset_calib_white.value());
- }
-
- /* find white corner in dark area : TODO yet another flag */
- if ((dev->model->sensor_id == SensorId::CCD_HP2300 && dev->model->motor_id == MotorId::HP2300) ||
- (dev->model->sensor_id == SensorId::CCD_HP2400 && dev->model->motor_id == MotorId::HP2400) ||
- (dev->model->sensor_id == SensorId::CCD_HP3670 && dev->model->motor_id == MotorId::HP3670))
- {
- top = 0;
- count = 0;
- for (x = 10; x < 60; x++)
- {
- y = 2;
- while ((y < height) && (image[x + y * width] < level))
- y++;
- top += y;
- count++;
- }
- top = top / count;
- dev->model->y_offset_calib_white = (top * MM_PER_INCH) / dpi;
- DBG(DBG_info, "%s: white corner y_offset = %f mm\n", __func__,
- dev->model->y_offset_calib_white.value());
- }
-
- DBG(DBG_proc, "%s: ccd_start_xoffset = %d, left = %d, top = %d\n", __func__,
- sensor.ccd_start_xoffset, left, top);
-}
-
-namespace gl843 {
- void gl843_park_xpa_lamp(Genesys_Device* dev);
- void gl843_set_xpa_motor_power(Genesys_Device* dev, Genesys_Register_Set& regs, bool set);
-} // namespace gl843
-
namespace gl124 {
void gl124_setup_scan_gpio(Genesys_Device* dev, int resolution);
} // namespace gl124
@@ -730,6 +473,16 @@ namespace gl124 {
void scanner_clear_scan_and_feed_counts(Genesys_Device& dev)
{
switch (dev.model->asic_type) {
+ case AsicType::GL841: {
+ dev.interface->write_register(gl841::REG_0x0D,
+ gl841::REG_0x0D_CLRLNCNT);
+ break;
+ }
+ case AsicType::GL842: {
+ dev.interface->write_register(gl842::REG_0x0D,
+ gl842::REG_0x0D_CLRLNCNT);
+ break;
+ }
case AsicType::GL843: {
dev.interface->write_register(gl843::REG_0x0D,
gl843::REG_0x0D_CLRLNCNT | gl843::REG_0x0D_CLRMCNT);
@@ -756,34 +509,107 @@ void scanner_clear_scan_and_feed_counts(Genesys_Device& dev)
}
}
-void scanner_clear_scan_and_feed_counts2(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)
{
- // FIXME: switch to scanner_clear_scan_and_feed_counts when updating tests
- switch (dev.model->asic_type) {
- case AsicType::GL843: {
- dev.interface->write_register(gl843::REG_0x0D, gl843::REG_0x0D_CLRLNCNT);
- dev.interface->write_register(gl843::REG_0x0D, gl843::REG_0x0D_CLRMCNT);
+ DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %zu", table_nr, slope_table.size());
+
+ unsigned max_table_nr = 0;
+ switch (dev->model->asic_type) {
+ case AsicType::GL646: {
+ max_table_nr = 2;
break;
}
+ case AsicType::GL841:
+ case AsicType::GL842:
+ case AsicType::GL843:
case AsicType::GL845:
- case AsicType::GL846: {
- dev.interface->write_register(gl846::REG_0x0D, gl846::REG_0x0D_CLRLNCNT);
- dev.interface->write_register(gl846::REG_0x0D, gl846::REG_0x0D_CLRMCNT);
+ case AsicType::GL846:
+ case AsicType::GL847:
+ case AsicType::GL124: {
+ max_table_nr = 4;
break;
}
- case AsicType::GL847: {
- dev.interface->write_register(gl847::REG_0x0D, gl847::REG_0x0D_CLRLNCNT);
- dev.interface->write_register(gl847::REG_0x0D, gl847::REG_0x0D_CLRMCNT);
+ default:
+ throw SaneException("Unsupported ASIC type");
+ }
+
+ if (table_nr > max_table_nr) {
+ throw SaneException("invalid table number %d", table_nr);
+ }
+
+ std::vector<uint8_t> table;
+ table.reserve(slope_table.size() * 2);
+ for (std::size_t i = 0; i < slope_table.size(); i++) {
+ table.push_back(slope_table[i] & 0xff);
+ table.push_back(slope_table[i] >> 8);
+ }
+ if (dev->model->asic_type == AsicType::GL841 ||
+ dev->model->model_id == ModelId::CANON_LIDE_90)
+ {
+ // BUG: do this on all gl842 scanners
+ auto max_table_size = get_slope_table_max_size(dev->model->asic_type);
+ table.reserve(max_table_size * 2);
+ while (table.size() < max_table_size * 2) {
+ table.push_back(slope_table.back() & 0xff);
+ table.push_back(slope_table.back() >> 8);
+ }
+ }
+
+ if (dev->interface->is_mock()) {
+ dev->interface->record_slope_table(table_nr, slope_table);
+ }
+
+ switch (dev->model->asic_type) {
+ case AsicType::GL646: {
+ unsigned dpihw = dev->reg.find_reg(0x05).value >> 6;
+ unsigned start_address = 0;
+ if (dpihw == 0) { // 600 dpi
+ start_address = 0x08000;
+ } else if (dpihw == 1) { // 1200 dpi
+ start_address = 0x10000;
+ } else if (dpihw == 2) { // 2400 dpi
+ start_address = 0x1f800;
+ } else {
+ throw SaneException("Unexpected dpihw");
+ }
+ dev->interface->write_buffer(0x3c, start_address + table_nr * 0x100, table.data(),
+ table.size());
break;
}
+ case AsicType::GL841:
+ case AsicType::GL842: {
+ unsigned start_address = 0;
+ switch (sensor.register_dpihw) {
+ case 600: start_address = 0x08000; break;
+ case 1200: start_address = 0x10000; break;
+ case 2400: start_address = 0x20000; break;
+ default: throw SaneException("Unexpected dpihw");
+ }
+ dev->interface->write_buffer(0x3c, start_address + table_nr * 0x200, table.data(),
+ table.size());
+ break;
+ }
+ case AsicType::GL843: {
+ // slope table addresses are fixed : 0x40000, 0x48000, 0x50000, 0x58000, 0x60000
+ // XXX STEF XXX USB 1.1 ? sanei_genesys_write_0x8c (dev, 0x0f, 0x14);
+ dev->interface->write_gamma(0x28, 0x40000 + 0x8000 * table_nr, table.data(),
+ table.size());
+ break;
+ }
+ case AsicType::GL845:
+ case AsicType::GL846:
+ case AsicType::GL847:
case AsicType::GL124: {
- dev.interface->write_register(gl124::REG_0x0D, gl124::REG_0x0D_CLRLNCNT);
- dev.interface->write_register(gl124::REG_0x0D, gl124::REG_0x0D_CLRMCNT);
+ // slope table addresses are fixed
+ dev->interface->write_ahb(0x10000000 + 0x4000 * table_nr, table.size(),
+ table.data());
break;
}
default:
- throw SaneException("Unsupported asic type");
+ throw SaneException("Unsupported ASIC type");
}
+
}
bool scanner_is_motor_stopped(Genesys_Device& dev)
@@ -794,9 +620,18 @@ bool scanner_is_motor_stopped(Genesys_Device& dev)
return !status.is_motor_enabled && status.is_feeding_finished;
}
case AsicType::GL841: {
+ auto status = scanner_read_status(dev);
auto reg = dev.interface->read_register(gl841::REG_0x40);
- return (!(reg & gl841::REG_0x40_DATAENB) && !(reg & gl841::REG_0x40_MOTMFLG));
+ return (!(reg & gl841::REG_0x40_DATAENB) && !(reg & gl841::REG_0x40_MOTMFLG) &&
+ !status.is_motor_enabled);
+ }
+ case AsicType::GL842: {
+ auto status = scanner_read_status(dev);
+ auto reg = dev.interface->read_register(gl842::REG_0x40);
+
+ return (!(reg & gl842::REG_0x40_DATAENB) && !(reg & gl842::REG_0x40_MOTMFLG) &&
+ !status.is_motor_enabled);
}
case AsicType::GL843: {
auto status = scanner_read_status(dev);
@@ -832,11 +667,31 @@ bool scanner_is_motor_stopped(Genesys_Device& dev)
}
}
+void scanner_setup_sensor(Genesys_Device& dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs)
+{
+ DBG_HELPER(dbg);
+
+ for (const auto& custom_reg : sensor.custom_regs) {
+ regs.set8(custom_reg.address, custom_reg.value);
+ }
+
+ if (dev.model->asic_type != AsicType::GL841 &&
+ dev.model->asic_type != AsicType::GL843)
+ {
+ regs_set_exposure(dev.model->asic_type, regs, sensor.exposure);
+ }
+
+ dev.segment_order = sensor.segment_order;
+}
+
void scanner_stop_action(Genesys_Device& dev)
{
DBG_HELPER(dbg);
switch (dev.model->asic_type) {
+ case AsicType::GL841:
+ case AsicType::GL842:
case AsicType::GL843:
case AsicType::GL845:
case AsicType::GL846:
@@ -847,9 +702,7 @@ void scanner_stop_action(Genesys_Device& dev)
throw SaneException("Unsupported asic type");
}
- if (dev.cmd_set->needs_update_home_sensor_gpio()) {
- dev.cmd_set->update_home_sensor_gpio(dev);
- }
+ dev.cmd_set->update_home_sensor_gpio(dev);
if (scanner_is_motor_stopped(dev)) {
DBG(DBG_info, "%s: already stopped\n", __func__);
@@ -878,6 +731,7 @@ void scanner_stop_action_no_move(Genesys_Device& dev, genesys::Genesys_Register_
switch (dev.model->asic_type) {
case AsicType::GL646:
case AsicType::GL841:
+ case AsicType::GL842:
case AsicType::GL843:
case AsicType::GL845:
case AsicType::GL846:
@@ -908,7 +762,9 @@ void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, D
const auto& sensor = sanei_genesys_find_sensor(&dev, resolution, 3, scan_method);
bool uses_secondary_head = (scan_method == ScanMethod::TRANSPARENCY ||
- scan_method == ScanMethod::TRANSPARENCY_INFRARED);
+ scan_method == ScanMethod::TRANSPARENCY_INFRARED) &&
+ (!has_flag(dev.model->flags, ModelFlag::UTA_NO_SECONDARY_MOTOR));
+
bool uses_secondary_pos = uses_secondary_head &&
dev.model->default_method == ScanMethod::FLATBED;
@@ -934,21 +790,19 @@ void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, D
session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = steps;
- session.params.pixels = 100;
+ session.params.pixels = 50;
session.params.lines = 3;
session.params.depth = 8;
- session.params.channels = 3;
+ session.params.channels = 1;
session.params.scan_method = scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- if (dev.model->asic_type == AsicType::GL843) {
- session.params.color_filter = ColorFilter::RED;
- } else {
- session.params.color_filter = dev.settings.color_filter;
- }
+ session.params.scan_mode = ScanColorMode::GRAY;
+ session.params.color_filter = ColorFilter::GREEN;
+
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::FEEDING |
- ScanFlag::IGNORE_LINE_DISTANCE;
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET;
if (dev.model->asic_type == AsicType::GL124) {
session.params.flags |= ScanFlag::DISABLE_BUFFER_FULL_MOVE;
@@ -963,20 +817,21 @@ void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, D
dev.cmd_set->init_regs_for_scan_session(&dev, sensor, &local_reg, session);
if (dev.model->asic_type != AsicType::GL843) {
- regs_set_exposure(dev.model->asic_type, local_reg, {0, 0, 0});
+ regs_set_exposure(dev.model->asic_type, local_reg,
+ sanei_genesys_fixup_exposure({0, 0, 0}));
}
- scanner_clear_scan_and_feed_counts2(dev);
+ scanner_clear_scan_and_feed_counts(dev);
dev.interface->write_registers(local_reg);
if (uses_secondary_head) {
- gl843::gl843_set_xpa_motor_power(&dev, local_reg, true);
+ dev.cmd_set->set_motor_mode(dev, local_reg, MotorMode::PRIMARY_AND_SECONDARY);
}
try {
scanner_start_action(dev, true);
} catch (...) {
catch_all_exceptions(__func__, [&]() {
- gl843::gl843_set_xpa_motor_power(&dev, local_reg, false);
+ dev.cmd_set->set_motor_mode(dev, local_reg, MotorMode::PRIMARY);
});
catch_all_exceptions(__func__, [&]() { scanner_stop_action(dev); });
// restore original registers
@@ -992,17 +847,18 @@ void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, D
dev.advance_head_pos_by_steps(ScanHeadId::SECONDARY, direction, steps);
}
- // FIXME: why don't we stop the scanner like on other ASICs
- if (dev.model->asic_type != AsicType::GL843) {
- scanner_stop_action(dev);
- }
+ scanner_stop_action(dev);
if (uses_secondary_head) {
- gl843::gl843_set_xpa_motor_power(&dev, local_reg, false);
+ dev.cmd_set->set_motor_mode(dev, local_reg, MotorMode::PRIMARY);
}
return;
}
// wait until feed count reaches the required value
+ if (dev.model->model_id == ModelId::CANON_LIDE_700F) {
+ dev.cmd_set->update_home_sensor_gpio(dev);
+ }
+
// FIXME: should porbably wait for some timeout
Status status;
for (unsigned i = 0;; ++i) {
@@ -1015,12 +871,9 @@ void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, D
dev.interface->sleep_ms(10);
}
- // FIXME: why don't we stop the scanner like on other ASICs
- if (dev.model->asic_type != AsicType::GL843) {
- scanner_stop_action(dev);
- }
+ scanner_stop_action(dev);
if (uses_secondary_head) {
- gl843::gl843_set_xpa_motor_power(&dev, local_reg, false);
+ dev.cmd_set->set_motor_mode(dev, local_reg, MotorMode::PRIMARY);
}
dev.advance_head_pos_by_steps(ScanHeadId::PRIMARY, direction, steps);
@@ -1032,11 +885,22 @@ void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, D
dev.interface->sleep_ms(100);
}
+void scanner_move_to_ta(Genesys_Device& dev)
+{
+ DBG_HELPER(dbg);
+
+ unsigned feed = static_cast<unsigned>((dev.model->y_offset_sensor_to_ta * dev.motor.base_ydpi) /
+ MM_PER_INCH);
+ scanner_move(dev, dev.model->default_method, feed, Direction::FORWARD);
+}
+
void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home)
{
DBG_HELPER_ARGS(dbg, "wait_until_home = %d", wait_until_home);
switch (dev.model->asic_type) {
+ case AsicType::GL841:
+ case AsicType::GL842:
case AsicType::GL843:
case AsicType::GL845:
case AsicType::GL846:
@@ -1047,11 +911,17 @@ void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home)
throw SaneException("Unsupported asic type");
}
+ if (dev.model->is_sheetfed) {
+ dbg.vlog(DBG_proc, "sheetfed scanner, skipping going back home");
+ return;
+ }
+
// FIXME: also check whether the scanner actually has a secondary head
- if (!dev.is_head_pos_known(ScanHeadId::SECONDARY) ||
+ if ((!dev.is_head_pos_known(ScanHeadId::SECONDARY) ||
dev.head_pos(ScanHeadId::SECONDARY) > 0 ||
dev.settings.scan_method == ScanMethod::TRANSPARENCY ||
- dev.settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ dev.settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) &&
+ (!has_flag(dev.model->flags, ModelFlag::UTA_NO_SECONDARY_MOTOR)))
{
scanner_move_back_home_ta(dev);
}
@@ -1064,9 +934,7 @@ void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home)
Direction::BACKWARD);
}
- if (dev.cmd_set->needs_update_home_sensor_gpio()) {
- dev.cmd_set->update_home_sensor_gpio(dev);
- }
+ dev.cmd_set->update_home_sensor_gpio(dev);
auto status = scanner_read_reliable_status(dev);
@@ -1076,15 +944,6 @@ void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home)
return;
}
- if (dev.model->model_id == ModelId::CANON_LIDE_210) {
- // move the head back a little first
- if (dev.is_head_pos_known(ScanHeadId::PRIMARY) &&
- dev.head_pos(ScanHeadId::PRIMARY) > 30)
- {
- scanner_move(dev, dev.model->default_method, 20, Direction::BACKWARD);
- }
- }
-
Genesys_Register_Set local_reg = dev.reg;
unsigned resolution = sanei_genesys_get_lowest_ydpi(&dev);
@@ -1093,28 +952,22 @@ void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home)
ScanSession session;
session.params.xres = resolution;
session.params.yres = resolution;
- session.params.startx = 100;
- if (dev.model->asic_type == AsicType::GL843) {
- session.params.starty = 40000;
- } else {
- session.params.starty = 30000;
- }
- session.params.pixels = 100;
- session.params.lines = 100;
+ session.params.startx = 0;
+ session.params.starty = 40000;
+ session.params.pixels = 50;
+ session.params.lines = 3;
session.params.depth = 8;
session.params.channels = 1;
session.params.scan_method = dev.settings.scan_method;
- if (dev.model->asic_type == AsicType::GL843) {
- session.params.scan_mode = ScanColorMode::LINEART;
- session.params.color_filter = dev.settings.color_filter;
- } else {
- session.params.scan_mode = ScanColorMode::GRAY;
- session.params.color_filter = ColorFilter::RED;
- }
+ session.params.scan_mode = ScanColorMode::GRAY;
+ session.params.color_filter = ColorFilter::GREEN;
+
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
- ScanFlag::IGNORE_LINE_DISTANCE |
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET |
ScanFlag::REVERSE;
+
if (dev.model->asic_type == AsicType::GL843) {
session.params.flags |= ScanFlag::DISABLE_BUFFER_FULL_MOVE;
}
@@ -1143,9 +996,7 @@ void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home)
throw;
}
- if (dev.cmd_set->needs_update_home_sensor_gpio()) {
- dev.cmd_set->update_home_sensor_gpio(dev);
- }
+ dev.cmd_set->update_home_sensor_gpio(dev);
if (is_testing_mode()) {
dev.interface->test_checkpoint("move_back_home");
@@ -1174,18 +1025,49 @@ void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home)
// when we come here then the scanner needed too much time for this, so we better stop
// the motor
catch_all_exceptions(__func__, [&](){ scanner_stop_action(dev); });
- dev.set_head_pos_unknown();
+ dev.set_head_pos_unknown(ScanHeadId::PRIMARY | ScanHeadId::SECONDARY);
throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home");
}
dbg.log(DBG_info, "scanhead is still moving");
}
+namespace {
+ bool should_use_secondary_motor_mode(Genesys_Device& dev)
+ {
+ bool should_use = !dev.is_head_pos_known(ScanHeadId::SECONDARY) ||
+ !dev.is_head_pos_known(ScanHeadId::PRIMARY) ||
+ dev.head_pos(ScanHeadId::SECONDARY) > dev.head_pos(ScanHeadId::PRIMARY);
+ bool supports = dev.model->model_id == ModelId::CANON_8600F;
+ return should_use && supports;
+ }
+
+ void handle_motor_position_after_move_back_home_ta(Genesys_Device& dev, MotorMode motor_mode)
+ {
+ if (motor_mode == MotorMode::SECONDARY) {
+ dev.set_head_pos_zero(ScanHeadId::SECONDARY);
+ return;
+ }
+
+ if (dev.is_head_pos_known(ScanHeadId::PRIMARY)) {
+ if (dev.head_pos(ScanHeadId::PRIMARY) > dev.head_pos(ScanHeadId::SECONDARY)) {
+ dev.advance_head_pos_by_steps(ScanHeadId::PRIMARY, Direction::BACKWARD,
+ dev.head_pos(ScanHeadId::SECONDARY));
+ } else {
+ dev.set_head_pos_zero(ScanHeadId::PRIMARY);
+ }
+ dev.set_head_pos_zero(ScanHeadId::SECONDARY);
+ }
+ }
+} // namespace
+
void scanner_move_back_home_ta(Genesys_Device& dev)
{
DBG_HELPER(dbg);
switch (dev.model->asic_type) {
+ case AsicType::GL842:
case AsicType::GL843:
+ case AsicType::GL845:
break;
default:
throw SaneException("Unsupported asic type");
@@ -1199,7 +1081,9 @@ void scanner_move_back_home_ta(Genesys_Device& dev)
const auto& sensor = sanei_genesys_find_sensor(&dev, resolution, 1, scan_method);
if (dev.is_head_pos_known(ScanHeadId::SECONDARY) &&
- dev.head_pos(ScanHeadId::SECONDARY) > 1000)
+ dev.is_head_pos_known(ScanHeadId::PRIMARY) &&
+ dev.head_pos(ScanHeadId::SECONDARY) > 1000 &&
+ dev.head_pos(ScanHeadId::SECONDARY) <= dev.head_pos(ScanHeadId::PRIMARY))
{
// leave 500 steps for regular slow back home
scanner_move(dev, scan_method, dev.head_pos(ScanHeadId::SECONDARY) - 500,
@@ -1209,18 +1093,20 @@ void scanner_move_back_home_ta(Genesys_Device& dev)
ScanSession session;
session.params.xres = resolution;
session.params.yres = resolution;
- session.params.startx = 100;
- session.params.starty = 30000;
- session.params.pixels = 100;
- session.params.lines = 100;
+ session.params.startx = 0;
+ session.params.starty = 40000;
+ session.params.pixels = 50;
+ session.params.lines = 3;
session.params.depth = 8;
session.params.channels = 1;
session.params.scan_method = scan_method;
session.params.scan_mode = ScanColorMode::GRAY;
- session.params.color_filter = ColorFilter::RED;
+ session.params.color_filter = ColorFilter::GREEN;
+
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
- ScanFlag::IGNORE_LINE_DISTANCE |
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET |
ScanFlag::REVERSE;
compute_session(&dev, session, sensor);
@@ -1230,7 +1116,11 @@ void scanner_move_back_home_ta(Genesys_Device& dev)
scanner_clear_scan_and_feed_counts(dev);
dev.interface->write_registers(local_reg);
- gl843::gl843_set_xpa_motor_power(&dev, local_reg, true);
+
+ auto motor_mode = should_use_secondary_motor_mode(dev) ? MotorMode::SECONDARY
+ : MotorMode::PRIMARY_AND_SECONDARY;
+
+ dev.cmd_set->set_motor_mode(dev, local_reg, motor_mode);
try {
scanner_start_action(dev, true);
@@ -1244,18 +1134,10 @@ void scanner_move_back_home_ta(Genesys_Device& dev)
if (is_testing_mode()) {
dev.interface->test_checkpoint("move_back_home_ta");
- if (dev.is_head_pos_known(ScanHeadId::PRIMARY)) {
- if (dev.head_pos(ScanHeadId::PRIMARY) > dev.head_pos(ScanHeadId::SECONDARY)) {
- dev.advance_head_pos_by_steps(ScanHeadId::PRIMARY, Direction::BACKWARD,
- dev.head_pos(ScanHeadId::SECONDARY));
- } else {
- dev.set_head_pos_zero(ScanHeadId::PRIMARY);
- }
- dev.set_head_pos_zero(ScanHeadId::SECONDARY);
- }
+ handle_motor_position_after_move_back_home_ta(dev, motor_mode);
scanner_stop_action(dev);
- gl843::gl843_set_xpa_motor_power(&dev, local_reg, false);
+ dev.cmd_set->set_motor_mode(dev, local_reg, MotorMode::PRIMARY);
return;
}
@@ -1266,18 +1148,10 @@ void scanner_move_back_home_ta(Genesys_Device& dev)
if (status.is_at_home) {
dbg.log(DBG_info, "TA reached home position");
- if (dev.is_head_pos_known(ScanHeadId::PRIMARY)) {
- if (dev.head_pos(ScanHeadId::PRIMARY) > dev.head_pos(ScanHeadId::SECONDARY)) {
- dev.advance_head_pos_by_steps(ScanHeadId::PRIMARY, Direction::BACKWARD,
- dev.head_pos(ScanHeadId::SECONDARY));
- } else {
- dev.set_head_pos_zero(ScanHeadId::PRIMARY);
- }
- dev.set_head_pos_zero(ScanHeadId::SECONDARY);
- }
+ handle_motor_position_after_move_back_home_ta(dev, motor_mode);
scanner_stop_action(dev);
- gl843::gl843_set_xpa_motor_power(&dev, local_reg, false);
+ dev.cmd_set->set_motor_mode(dev, local_reg, MotorMode::PRIMARY);
return;
}
@@ -1287,325 +1161,1148 @@ void scanner_move_back_home_ta(Genesys_Device& dev)
throw SaneException("Timeout waiting for XPA lamp to park");
}
-void sanei_genesys_calculate_zmod(bool two_table,
- uint32_t exposure_time,
- const std::vector<uint16_t>& slope_table,
- unsigned acceleration_steps,
- unsigned move_steps,
- unsigned buffer_acceleration_steps,
- uint32_t* out_z1, uint32_t* out_z2)
+void scanner_search_strip(Genesys_Device& dev, bool forward, bool black)
{
- DBG(DBG_info, "%s: two_table=%d\n", __func__, two_table);
+ DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse");
- // acceleration total time
- unsigned sum = std::accumulate(slope_table.begin(), slope_table.begin() + acceleration_steps,
- 0, std::plus<unsigned>());
+ if (dev.model->asic_type == AsicType::GL841 && !black && forward) {
+ dev.frontend.set_gain(0, 0xff);
+ dev.frontend.set_gain(1, 0xff);
+ dev.frontend.set_gain(2, 0xff);
+ }
- /* Z1MOD:
- c = sum(slope_table; reg_stepno)
- d = reg_fwdstep * <cruising speed>
- Z1MOD = (c+d) % exposure_time
- */
- *out_z1 = (sum + buffer_acceleration_steps * slope_table[acceleration_steps - 1]) % exposure_time;
+ // set up for a gray scan at lowest dpi
+ const auto& resolution_settings = dev.model->get_resolution_settings(dev.settings.scan_method);
+ unsigned dpi = resolution_settings.get_min_resolution_x();
+ unsigned channels = 1;
- /* Z2MOD:
- a = sum(slope_table; reg_stepno)
- b = move_steps or 1 if 2 tables
- Z1MOD = (a+b) % exposure_time
- */
- if (!two_table) {
- sum = sum + (move_steps * slope_table[acceleration_steps - 1]);
+ auto& sensor = sanei_genesys_find_sensor(&dev, dpi, channels, dev.settings.scan_method);
+ dev.cmd_set->set_fe(&dev, sensor, AFE_SET);
+ scanner_stop_action(dev);
+
+
+ // shading calibration is done with dev.motor.base_ydpi
+ unsigned lines = static_cast<unsigned>(dev.model->y_size_calib_mm * dpi / MM_PER_INCH);
+ if (dev.model->asic_type == AsicType::GL841) {
+ lines = 10; // TODO: use dev.model->search_lines
+ lines = static_cast<unsigned>((lines * dpi) / MM_PER_INCH);
+ }
+
+ unsigned pixels = dev.model->x_size_calib_mm * dpi / MM_PER_INCH;
+
+ dev.set_head_pos_zero(ScanHeadId::PRIMARY);
+
+ unsigned length = 20;
+ if (dev.model->asic_type == AsicType::GL841) {
+ // 20 cm max length for calibration sheet
+ length = static_cast<unsigned>(((200 * dpi) / MM_PER_INCH) / lines);
+ }
+
+ auto local_reg = dev.reg;
+
+ ScanSession session;
+ session.params.xres = dpi;
+ session.params.yres = dpi;
+ session.params.startx = 0;
+ session.params.starty = 0;
+ session.params.pixels = pixels;
+ session.params.lines = lines;
+ session.params.depth = 8;
+ session.params.channels = channels;
+ session.params.scan_method = dev.settings.scan_method;
+ session.params.scan_mode = ScanColorMode::GRAY;
+ session.params.color_filter = ColorFilter::RED;
+ session.params.flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA;
+ if (dev.model->asic_type != AsicType::GL841 && !forward) {
+ session.params.flags |= ScanFlag::REVERSE;
+ }
+ compute_session(&dev, session, sensor);
+
+ dev.cmd_set->init_regs_for_scan_session(&dev, sensor, &local_reg, session);
+
+ dev.interface->write_registers(local_reg);
+
+ dev.cmd_set->begin_scan(&dev, sensor, &local_reg, true);
+
+ if (is_testing_mode()) {
+ dev.interface->test_checkpoint("search_strip");
+ scanner_stop_action(dev);
+ return;
+ }
+
+ wait_until_buffer_non_empty(&dev);
+
+ // now we're on target, we can read data
+ auto image = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes);
+
+ scanner_stop_action(dev);
+
+ unsigned pass = 0;
+ if (dbg_log_image_data()) {
+ char title[80];
+ std::sprintf(title, "gl_search_strip_%s_%s%02d.tiff",
+ black ? "black" : "white", forward ? "fwd" : "bwd", pass);
+ write_tiff_file(title, image);
+ }
+
+ // loop until strip is found or maximum pass number done
+ bool found = false;
+ while (pass < length && !found) {
+ dev.interface->write_registers(local_reg);
+
+ // now start scan
+ dev.cmd_set->begin_scan(&dev, sensor, &local_reg, true);
+
+ wait_until_buffer_non_empty(&dev);
+
+ // now we're on target, we can read data
+ image = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes);
+
+ scanner_stop_action(dev);
+
+ if (dbg_log_image_data()) {
+ char title[80];
+ std::sprintf(title, "gl_search_strip_%s_%s%02d.tiff",
+ black ? "black" : "white",
+ forward ? "fwd" : "bwd", static_cast<int>(pass));
+ write_tiff_file(title, image);
+ }
+
+ unsigned white_level = 90;
+ unsigned black_level = 60;
+
+ std::size_t count = 0;
+ // Search data to find black strip
+ // When searching forward, we only need one line of the searched color since we
+ // will scan forward. But when doing backward search, we need all the area of the ame color
+ if (forward) {
+
+ for (std::size_t y = 0; y < image.get_height() && !found; y++) {
+ count = 0;
+
+ // count of white/black pixels depending on the color searched
+ for (std::size_t x = 0; x < image.get_width(); x++) {
+
+ // when searching for black, detect white pixels
+ if (black && image.get_raw_channel(x, y, 0) > white_level) {
+ count++;
+ }
+
+ // when searching for white, detect black pixels
+ if (!black && image.get_raw_channel(x, y, 0) < black_level) {
+ count++;
+ }
+ }
+
+ // at end of line, if count >= 3%, line is not fully of the desired color
+ // so we must go to next line of the buffer */
+ // count*100/pixels < 3
+
+ auto found_percentage = (count * 100 / image.get_width());
+ if (found_percentage < 3) {
+ found = 1;
+ DBG(DBG_data, "%s: strip found forward during pass %d at line %zu\n", __func__,
+ pass, y);
+ } else {
+ DBG(DBG_data, "%s: pixels=%zu, count=%zu (%zu%%)\n", __func__,
+ image.get_width(), count, found_percentage);
+ }
+ }
+ } else {
+ /* since calibration scans are done forward, we need the whole area
+ to be of the required color when searching backward
+ */
+ count = 0;
+ for (std::size_t y = 0; y < image.get_height(); y++) {
+ // count of white/black pixels depending on the color searched
+ for (std::size_t x = 0; x < image.get_width(); x++) {
+ // when searching for black, detect white pixels
+ if (black && image.get_raw_channel(x, y, 0) > white_level) {
+ count++;
+ }
+ // when searching for white, detect black pixels
+ if (!black && image.get_raw_channel(x, y, 0) < black_level) {
+ count++;
+ }
+ }
+ }
+
+ // at end of area, if count >= 3%, area is not fully of the desired color
+ // so we must go to next buffer
+ auto found_percentage = count * 100 / (image.get_width() * image.get_height());
+ if (found_percentage < 3) {
+ found = 1;
+ DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass);
+ } else {
+ DBG(DBG_data, "%s: pixels=%zu, count=%zu (%zu%%)\n", __func__, image.get_width(),
+ count, found_percentage);
+ }
+ }
+ pass++;
+ }
+
+ if (found) {
+ DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white");
} else {
- sum = sum + slope_table[acceleration_steps - 1];
+ throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found",
+ black ? "black" : "white");
}
- *out_z2 = sum % exposure_time;
}
-static uint8_t genesys_adjust_gain(double* applied_multi, double multi, uint8_t gain)
+static int dark_average_channel(const Image& image, unsigned black, unsigned channel)
+{
+ auto channels = get_pixel_channels(image.get_format());
+
+ unsigned avg[3];
+
+ // computes average values on black margin
+ for (unsigned ch = 0; ch < channels; ch++) {
+ avg[ch] = 0;
+ unsigned count = 0;
+ // FIXME: start with the second line because the black pixels often have noise on the first
+ // line; the cause is probably incorrectly cleaned up previous scan
+ for (std::size_t y = 1; y < image.get_height(); y++) {
+ for (unsigned j = 0; j < black; j++) {
+ avg[ch] += image.get_raw_channel(j, y, ch);
+ count++;
+ }
+ }
+ if (count > 0) {
+ avg[ch] /= count;
+ }
+ DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, ch, avg[ch]);
+ }
+ DBG(DBG_info, "%s: average = %d\n", __func__, avg[channel]);
+ return avg[channel];
+}
+
+bool should_calibrate_only_active_area(const Genesys_Device& dev,
+ const Genesys_Settings& settings)
{
- double voltage, original_voltage;
- uint8_t new_gain = 0;
+ if (settings.scan_method == ScanMethod::TRANSPARENCY ||
+ settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ if (dev.model->model_id == ModelId::CANON_4400F && settings.xres >= 4800) {
+ return true;
+ }
+ if (dev.model->model_id == ModelId::CANON_8600F && settings.xres == 4800) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs)
+{
+ DBG_HELPER(dbg);
+
+ if (dev.model->asic_type == AsicType::GL842 &&
+ dev.frontend.layout.type != FrontendType::WOLFSON)
+ {
+ return;
+ }
+
+ if (dev.model->asic_type == AsicType::GL843 &&
+ dev.frontend.layout.type != FrontendType::WOLFSON)
+ {
+ return;
+ }
+
+ if (dev.model->asic_type == AsicType::GL845 ||
+ dev.model->asic_type == AsicType::GL846)
+ {
+ // no gain nor offset for AKM AFE
+ std::uint8_t reg04 = dev.interface->read_register(gl846::REG_0x04);
+ if ((reg04 & gl846::REG_0x04_FESET) == 0x02) {
+ return;
+ }
+ }
+ if (dev.model->asic_type == AsicType::GL847) {
+ // no gain nor offset for AKM AFE
+ std::uint8_t reg04 = dev.interface->read_register(gl847::REG_0x04);
+ if ((reg04 & gl847::REG_0x04_FESET) == 0x02) {
+ return;
+ }
+ }
- DBG(DBG_proc, "%s: multi=%f, gain=%d\n", __func__, multi, gain);
+ if (dev.model->asic_type == AsicType::GL124) {
+ std::uint8_t reg0a = dev.interface->read_register(gl124::REG_0x0A);
+ if (((reg0a & gl124::REG_0x0A_SIFSEL) >> gl124::REG_0x0AS_SIFSEL) == 3) {
+ return;
+ }
+ }
- voltage = 0.5 + gain * 0.25;
- original_voltage = voltage;
+ unsigned target_pixels = dev.model->x_size_calib_mm * sensor.full_resolution / MM_PER_INCH;
+ unsigned start_pixel = 0;
+ unsigned black_pixels = (sensor.black_pixels * sensor.full_resolution) / sensor.full_resolution;
- voltage *= multi;
+ unsigned channels = 3;
+ unsigned lines = 1;
+ unsigned resolution = sensor.full_resolution;
- new_gain = static_cast<std::uint8_t>((voltage - 0.5) * 4);
- if (new_gain > 0x0e)
- new_gain = 0x0e;
+ const Genesys_Sensor* calib_sensor = &sensor;
+ if (dev.model->asic_type == AsicType::GL843) {
+ lines = 8;
- voltage = 0.5 + (new_gain) * 0.25;
+ // compute divider factor to compute final pixels number
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(&dev, dev.settings.xres, channels,
+ dev.settings.scan_method);
+ resolution = dpihw_sensor.shading_resolution;
+ unsigned factor = sensor.full_resolution / resolution;
- *applied_multi = voltage / original_voltage;
+ calib_sensor = &sanei_genesys_find_sensor(&dev, resolution, channels,
+ dev.settings.scan_method);
- DBG(DBG_proc, "%s: orig voltage=%.2f, new voltage=%.2f, *applied_multi=%f, new_gain=%d\n",
- __func__, original_voltage, voltage, *applied_multi, new_gain);
+ target_pixels = dev.model->x_size_calib_mm * resolution / MM_PER_INCH;
+ black_pixels = calib_sensor->black_pixels / factor;
- return new_gain;
-}
+ if (should_calibrate_only_active_area(dev, dev.settings)) {
+ float offset = dev.model->x_offset_ta;
+ start_pixel = static_cast<int>((offset * calib_sensor->get_optical_resolution()) / MM_PER_INCH);
+ float size = dev.model->x_size_ta;
+ target_pixels = static_cast<int>((size * calib_sensor->get_optical_resolution()) / MM_PER_INCH);
+ }
-// todo: is return status necessary (unchecked?)
-static void genesys_average_white(Genesys_Device* dev, Genesys_Sensor& sensor, int channels,
- int channel, uint8_t* data, int size, int *max_average)
-{
+ if (dev.model->model_id == ModelId::CANON_4400F &&
+ dev.settings.scan_method == ScanMethod::FLATBED)
+ {
+ return;
+ }
+ }
- DBG_HELPER_ARGS(dbg, "channels=%d, channel=%d, size=%d", channels, channel, size);
- int gain_white_ref, sum, range;
- int average;
- int i;
+ if (dev.model->model_id == ModelId::CANON_5600F) {
+ // FIXME: use same approach as for GL843 scanners
+ lines = 8;
+ }
- range = size / 50;
+ if (dev.model->asic_type == AsicType::GL847) {
+ calib_sensor = &sanei_genesys_find_sensor(&dev, resolution, channels,
+ dev.settings.scan_method);
+ }
- if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
- dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ ScanFlag flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA |
+ ScanFlag::SINGLE_LINE |
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET;
+
+ if (dev.settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev.settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
- gain_white_ref = sensor.fau_gain_white_ref * 256;
+ flags |= ScanFlag::USE_XPA;
+ }
+
+ ScanSession session;
+ session.params.xres = resolution;
+ session.params.yres = resolution;
+ session.params.startx = start_pixel;
+ session.params.starty = 0;
+ session.params.pixels = target_pixels;
+ session.params.lines = lines;
+ session.params.depth = 8;
+ session.params.channels = channels;
+ session.params.scan_method = dev.settings.scan_method;
+ session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
+ session.params.color_filter = dev.model->asic_type == AsicType::GL843 ? ColorFilter::RED
+ : dev.settings.color_filter;
+ session.params.flags = flags;
+ compute_session(&dev, session, *calib_sensor);
+
+ dev.cmd_set->init_regs_for_scan_session(&dev, *calib_sensor, &regs, session);
+
+ unsigned output_pixels = session.output_pixels;
+
+ sanei_genesys_set_motor_power(regs, false);
+
+ int top[3], bottom[3];
+ int topavg[3], bottomavg[3], avg[3];
+
+ // init gain and offset
+ for (unsigned ch = 0; ch < 3; ch++)
+ {
+ bottom[ch] = 10;
+ dev.frontend.set_offset(ch, bottom[ch]);
+ dev.frontend.set_gain(ch, 0);
+ }
+ dev.cmd_set->set_fe(&dev, *calib_sensor, AFE_SET);
+
+ // scan with bottom AFE settings
+ dev.interface->write_registers(regs);
+ DBG(DBG_info, "%s: starting first line reading\n", __func__);
+
+ dev.cmd_set->begin_scan(&dev, *calib_sensor, &regs, true);
+
+ if (is_testing_mode()) {
+ dev.interface->test_checkpoint("offset_calibration");
+ if (dev.model->asic_type == AsicType::GL842 ||
+ dev.model->asic_type == AsicType::GL843)
+ {
+ scanner_stop_action_no_move(dev, regs);
+ }
+ return;
+ }
+
+ Image first_line;
+ if (dev.model->asic_type == AsicType::GL842 ||
+ dev.model->asic_type == AsicType::GL843)
+ {
+ first_line = read_unshuffled_image_from_scanner(&dev, session,
+ session.output_total_bytes_raw);
+ scanner_stop_action_no_move(dev, regs);
} else {
- gain_white_ref = sensor.gain_white_ref * 256;
+ first_line = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes);
+
+ if (dev.model->model_id == ModelId::CANON_5600F) {
+ scanner_stop_action_no_move(dev, regs);
+ }
+ }
+
+ if (dbg_log_image_data()) {
+ char fn[40];
+ std::snprintf(fn, 40, "gl843_bottom_offset_%03d_%03d_%03d.tiff",
+ bottom[0], bottom[1], bottom[2]);
+ write_tiff_file(fn, first_line);
}
- if (range < 1)
- range = 1;
+ for (unsigned ch = 0; ch < 3; ch++) {
+ bottomavg[ch] = dark_average_channel(first_line, black_pixels, ch);
+ DBG(DBG_info, "%s: bottom avg %d=%d\n", __func__, ch, bottomavg[ch]);
+ }
- size = size / (2 * range * channels);
+ // now top value
+ for (unsigned ch = 0; ch < 3; ch++) {
+ top[ch] = 255;
+ dev.frontend.set_offset(ch, top[ch]);
+ }
+ dev.cmd_set->set_fe(&dev, *calib_sensor, AFE_SET);
- data += (channel * 2);
+ // scan with top AFE values
+ dev.interface->write_registers(regs);
+ DBG(DBG_info, "%s: starting second line reading\n", __func__);
- *max_average = 0;
+ dev.cmd_set->begin_scan(&dev, *calib_sensor, &regs, true);
- while (size--)
+ Image second_line;
+ if (dev.model->asic_type == AsicType::GL842 ||
+ dev.model->asic_type == AsicType::GL843)
{
- sum = 0;
- for (i = 0; i < range; i++)
- {
- sum += (*data);
- sum += *(data + 1) * 256;
- data += (2 * channels); /* byte based */
- }
+ second_line = read_unshuffled_image_from_scanner(&dev, session,
+ session.output_total_bytes_raw);
+ scanner_stop_action_no_move(dev, regs);
+ } else {
+ second_line = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes);
- average = (sum / range);
- if (average > *max_average)
- *max_average = average;
+ if (dev.model->model_id == ModelId::CANON_5600F) {
+ scanner_stop_action_no_move(dev, regs);
+ }
}
- DBG(DBG_proc, "%s: max_average=%d, gain_white_ref = %d, finished\n", __func__, *max_average,
- gain_white_ref);
+ for (unsigned ch = 0; ch < 3; ch++){
+ topavg[ch] = dark_average_channel(second_line, black_pixels, ch);
+ DBG(DBG_info, "%s: top avg %d=%d\n", __func__, ch, topavg[ch]);
+ }
+
+ unsigned pass = 0;
+
+ std::vector<std::uint8_t> debug_image;
+ std::size_t debug_image_lines = 0;
+ std::string debug_image_info;
- if (*max_average >= gain_white_ref)
- throw SaneException(SANE_STATUS_INVAL);
+ // loop until acceptable level
+ while ((pass < 32) && ((top[0] - bottom[0] > 1) ||
+ (top[1] - bottom[1] > 1) ||
+ (top[2] - bottom[2] > 1)))
+ {
+ pass++;
+
+ for (unsigned ch = 0; ch < 3; ch++) {
+ if (top[ch] - bottom[ch] > 1) {
+ dev.frontend.set_offset(ch, (top[ch] + bottom[ch]) / 2);
+ }
+ }
+ dev.cmd_set->set_fe(&dev, *calib_sensor, AFE_SET);
+
+ // scan with no move
+ dev.interface->write_registers(regs);
+ DBG(DBG_info, "%s: starting second line reading\n", __func__);
+ dev.cmd_set->begin_scan(&dev, *calib_sensor, &regs, true);
+
+ if (dev.model->asic_type == AsicType::GL842 ||
+ dev.model->asic_type == AsicType::GL843)
+ {
+ second_line = read_unshuffled_image_from_scanner(&dev, session,
+ session.output_total_bytes_raw);
+ scanner_stop_action_no_move(dev, regs);
+ } else {
+ second_line = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes);
+
+ if (dev.model->model_id == ModelId::CANON_5600F) {
+ scanner_stop_action_no_move(dev, regs);
+ }
+ }
+
+ if (dbg_log_image_data()) {
+ char title[100];
+ std::snprintf(title, 100, "lines: %d pixels_per_line: %d offsets[0..2]: %d %d %d\n",
+ lines, output_pixels,
+ dev.frontend.get_offset(0),
+ dev.frontend.get_offset(1),
+ dev.frontend.get_offset(2));
+ debug_image_info += title;
+ std::copy(second_line.get_row_ptr(0),
+ second_line.get_row_ptr(0) + second_line.get_row_bytes() * second_line.get_height(),
+ std::back_inserter(debug_image));
+ debug_image_lines += lines;
+ }
+
+ for (unsigned ch = 0; ch < 3; ch++) {
+ avg[ch] = dark_average_channel(second_line, black_pixels, ch);
+ DBG(DBG_info, "%s: avg[%d]=%d offset=%d\n", __func__, ch, avg[ch],
+ dev.frontend.get_offset(ch));
+ }
+
+ // compute new boundaries
+ for (unsigned ch = 0; ch < 3; ch++) {
+ if (topavg[ch] >= avg[ch]) {
+ topavg[ch] = avg[ch];
+ top[ch] = dev.frontend.get_offset(ch);
+ } else {
+ bottomavg[ch] = avg[ch];
+ bottom[ch] = dev.frontend.get_offset(ch);
+ }
+ }
+ }
+
+ if (dbg_log_image_data()) {
+ sanei_genesys_write_file("gl_offset_all_desc.txt",
+ reinterpret_cast<const std::uint8_t*>(debug_image_info.data()),
+ debug_image_info.size());
+ write_tiff_file("gl_offset_all.tiff", debug_image.data(), session.params.depth, channels,
+ output_pixels, debug_image_lines);
+ }
+
+ DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
+ dev.frontend.get_offset(0),
+ dev.frontend.get_offset(1),
+ dev.frontend.get_offset(2));
}
-/* todo: understand, values are too high */
-static int
-genesys_average_black (Genesys_Device * dev, int channel,
- uint8_t * data, int pixels)
+/* With offset and coarse calibration we only want to get our input range into
+ a reasonable shape. the fine calibration of the upper and lower bounds will
+ be done with shading.
+*/
+void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs, unsigned dpi)
{
- int i;
- int sum;
- int pixel_step;
+ DBG_HELPER_ARGS(dbg, "dpi = %d", dpi);
- DBG(DBG_proc, "%s: channel=%d, pixels=%d\n", __func__, channel, pixels);
+ if (dev.model->asic_type == AsicType::GL842 &&
+ dev.frontend.layout.type != FrontendType::WOLFSON)
+ {
+ return;
+ }
- sum = 0;
+ if (dev.model->asic_type == AsicType::GL843 &&
+ dev.frontend.layout.type != FrontendType::WOLFSON)
+ {
+ return;
+ }
- if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS)
+ if (dev.model->asic_type == AsicType::GL845 ||
+ dev.model->asic_type == AsicType::GL846)
{
- data += (channel * 2);
- pixel_step = 3 * 2;
+ // no gain nor offset for AKM AFE
+ std::uint8_t reg04 = dev.interface->read_register(gl846::REG_0x04);
+ if ((reg04 & gl846::REG_0x04_FESET) == 0x02) {
+ return;
+ }
}
- else
+
+ if (dev.model->asic_type == AsicType::GL847) {
+ // no gain nor offset for AKM AFE
+ std::uint8_t reg04 = dev.interface->read_register(gl847::REG_0x04);
+ if ((reg04 & gl847::REG_0x04_FESET) == 0x02) {
+ return;
+ }
+ }
+
+ if (dev.model->asic_type == AsicType::GL124) {
+ // no gain nor offset for TI AFE
+ std::uint8_t reg0a = dev.interface->read_register(gl124::REG_0x0A);
+ if (((reg0a & gl124::REG_0x0A_SIFSEL) >> gl124::REG_0x0AS_SIFSEL) == 3) {
+ return;
+ }
+ }
+
+ if (dev.model->asic_type == AsicType::GL841) {
+ // feed to white strip if needed
+ if (dev.model->y_offset_calib_white > 0) {
+ unsigned move = static_cast<unsigned>(
+ (dev.model->y_offset_calib_white * (dev.motor.base_ydpi)) / MM_PER_INCH);
+ scanner_move(dev, dev.model->default_method, move, Direction::FORWARD);
+ }
+ }
+
+ // coarse gain calibration is always done in color mode
+ unsigned channels = 3;
+
+ unsigned resolution = sensor.full_resolution;
+ if (dev.model->asic_type == AsicType::GL841) {
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(&dev, dev.settings.xres, channels,
+ dev.settings.scan_method);
+ resolution = dpihw_sensor.shading_resolution;
+ }
+
+ if (dev.model->asic_type == AsicType::GL842 ||
+ dev.model->asic_type == AsicType::GL843)
{
- pixel_step = 2;
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(&dev, dpi, channels,
+ dev.settings.scan_method);
+ resolution = dpihw_sensor.shading_resolution;
}
- for (i = 0; i < pixels; i++)
+ float coeff = 1;
+
+ // Follow CKSEL
+ if (dev.model->sensor_id == SensorId::CCD_KVSS080 ||
+ dev.model->asic_type == AsicType::GL845 ||
+ dev.model->asic_type == AsicType::GL846 ||
+ dev.model->asic_type == AsicType::GL847 ||
+ dev.model->asic_type == AsicType::GL124)
{
- sum += *data;
- sum += *(data + 1) * 256;
+ if (dev.settings.xres < sensor.full_resolution) {
+ coeff = 0.9f;
+ }
+ }
- data += pixel_step;
+ unsigned lines = 10;
+ if (dev.model->asic_type == AsicType::GL841) {
+ lines = 1;
}
- DBG(DBG_proc, "%s = %d\n", __func__, sum / pixels);
+ const Genesys_Sensor* calib_sensor = &sensor;
+ if (dev.model->asic_type == AsicType::GL841 ||
+ dev.model->asic_type == AsicType::GL842 ||
+ dev.model->asic_type == AsicType::GL843 ||
+ dev.model->asic_type == AsicType::GL847)
+ {
+ calib_sensor = &sanei_genesys_find_sensor(&dev, resolution, channels,
+ dev.settings.scan_method);
+ }
- return sum / pixels;
+ ScanFlag flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA |
+ ScanFlag::SINGLE_LINE |
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET;
+
+ if (dev.settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev.settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ flags |= ScanFlag::USE_XPA;
+ }
+
+ ScanSession session;
+ session.params.xres = resolution;
+ session.params.yres = dev.model->asic_type == AsicType::GL841 ? dev.settings.yres : resolution;
+ session.params.startx = 0;
+ session.params.starty = 0;
+ session.params.pixels = dev.model->x_size_calib_mm * resolution / MM_PER_INCH;
+ session.params.lines = lines;
+ session.params.depth = dev.model->asic_type == AsicType::GL841 ? 16 : 8;
+ session.params.channels = channels;
+ session.params.scan_method = dev.settings.scan_method;
+ session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
+ session.params.color_filter = dev.settings.color_filter;
+ session.params.flags = flags;
+ compute_session(&dev, session, *calib_sensor);
+
+ std::size_t pixels = session.output_pixels;
+
+ try {
+ dev.cmd_set->init_regs_for_scan_session(&dev, *calib_sensor, &regs, session);
+ } catch (...) {
+ if (dev.model->asic_type != AsicType::GL841) {
+ catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); });
+ }
+ throw;
+ }
+
+ if (dev.model->asic_type != AsicType::GL841) {
+ sanei_genesys_set_motor_power(regs, false);
+ }
+
+ dev.interface->write_registers(regs);
+
+ if (dev.model->asic_type != AsicType::GL841) {
+ dev.cmd_set->set_fe(&dev, *calib_sensor, AFE_SET);
+ }
+ dev.cmd_set->begin_scan(&dev, *calib_sensor, &regs, true);
+
+ if (is_testing_mode()) {
+ dev.interface->test_checkpoint("coarse_gain_calibration");
+ scanner_stop_action(dev);
+ dev.cmd_set->move_back_home(&dev, true);
+ return;
+ }
+
+ Image image;
+ if (dev.model->asic_type == AsicType::GL842 ||
+ dev.model->asic_type == AsicType::GL843)
+ {
+ image = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes_raw);
+ } else if (dev.model->asic_type == AsicType::GL124) {
+ // BUG: we probably want to read whole image, not just first line
+ image = read_unshuffled_image_from_scanner(&dev, session, session.output_line_bytes);
+ } else {
+ image = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes);
+ }
+
+ if (dev.model->asic_type == AsicType::GL842 ||
+ dev.model->asic_type == AsicType::GL843)
+ {
+ scanner_stop_action_no_move(dev, regs);
+ }
+
+ if (dbg_log_image_data()) {
+ write_tiff_file("gl_coarse_gain.tiff", image);
+ }
+
+ for (unsigned ch = 0; ch < channels; ch++) {
+ float curr_output = 0;
+ float target_value = 0;
+
+ if (dev.model->asic_type == AsicType::GL842 ||
+ dev.model->asic_type == AsicType::GL843)
+ {
+ std::vector<uint16_t> values;
+ // FIXME: start from the second line because the first line often has artifacts. Probably
+ // caused by unclean cleanup of previous scan
+ for (std::size_t x = pixels / 4; x < (pixels * 3 / 4); x++) {
+ values.push_back(image.get_raw_channel(x, 1, ch));
+ }
+
+ // pick target value at 95th percentile of all values. There may be a lot of black values
+ // in transparency scans for example
+ std::sort(values.begin(), values.end());
+ curr_output = static_cast<float>(values[unsigned((values.size() - 1) * 0.95)]);
+ target_value = calib_sensor->gain_white_ref * coeff;
+
+ } else if (dev.model->asic_type == AsicType::GL841) {
+ // FIXME: use the GL843 approach
+ unsigned max = 0;
+ for (std::size_t x = 0; x < image.get_width(); x++) {
+ auto value = image.get_raw_channel(x, 0, ch);
+ if (value > max) {
+ max = value;
+ }
+ }
+
+ curr_output = max;
+ target_value = 65535.0f;
+ } else {
+ // FIXME: use the GL843 approach
+ auto width = image.get_width();
+
+ std::uint64_t total = 0;
+ for (std::size_t x = width / 4; x < (width * 3 / 4); x++) {
+ total += image.get_raw_channel(x, 0, ch);
+ }
+
+ curr_output = total / (width / 2);
+ target_value = calib_sensor->gain_white_ref * coeff;
+ }
+
+ std::uint8_t out_gain = compute_frontend_gain(curr_output, target_value,
+ dev.frontend.layout.type);
+ dev.frontend.set_gain(ch, out_gain);
+
+ DBG(DBG_proc, "%s: channel %d, curr=%f, target=%f, out_gain:%d\n", __func__, ch,
+ curr_output, target_value, out_gain);
+
+ if (dev.model->asic_type == AsicType::GL841 &&
+ target_value / curr_output > 30)
+ {
+ DBG(DBG_error0, "****************************************\n");
+ DBG(DBG_error0, "* *\n");
+ DBG(DBG_error0, "* Extremely low Brightness detected. *\n");
+ DBG(DBG_error0, "* Check the scanning head is *\n");
+ DBG(DBG_error0, "* unlocked and moving. *\n");
+ DBG(DBG_error0, "* *\n");
+ DBG(DBG_error0, "****************************************\n");
+ throw SaneException(SANE_STATUS_JAMMED, "scanning head is locked");
+ }
+
+ dbg.vlog(DBG_info, "gain=(%d, %d, %d)", dev.frontend.get_gain(0), dev.frontend.get_gain(1),
+ dev.frontend.get_gain(2));
+ }
+
+ if (dev.model->is_cis) {
+ std::uint8_t min_gain = std::min({dev.frontend.get_gain(0),
+ dev.frontend.get_gain(1),
+ dev.frontend.get_gain(2)});
+
+ dev.frontend.set_gain(0, min_gain);
+ dev.frontend.set_gain(1, min_gain);
+ dev.frontend.set_gain(2, min_gain);
+ }
+
+ dbg.vlog(DBG_info, "final gain=(%d, %d, %d)", dev.frontend.get_gain(0),
+ dev.frontend.get_gain(1), dev.frontend.get_gain(2));
+
+ scanner_stop_action(dev);
+
+ dev.cmd_set->move_back_home(&dev, true);
}
+namespace gl124 {
+ void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs);
+} // namespace gl124
-// todo: check; it works but the lines 1, 2, and 3 are too dark even with the
-// same offset and gain settings?
-static void genesys_coarse_calibration(Genesys_Device* dev, Genesys_Sensor& sensor)
+SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs)
{
- DBG_HELPER_ARGS(dbg, "scan_mode = %d", static_cast<unsigned>(dev->settings.scan_mode));
- int black_pixels;
- int white_average;
- uint8_t offset[4] = { 0xa0, 0x00, 0xa0, 0x40 }; /* first value isn't used */
- uint16_t white[12], dark[12];
- int i, j;
+ DBG_HELPER(dbg);
- black_pixels = sensor.black_pixels
- * dev->settings.xres / sensor.optical_res;
+ float move = 0;
- unsigned channels = dev->settings.get_channels();
+ if (dev.model->asic_type == AsicType::GL841) {
+ if (dev.model->y_offset_calib_white > 0) {
+ move = (dev.model->y_offset_calib_white * (dev.motor.base_ydpi)) / MM_PER_INCH;
+ scanner_move(dev, dev.model->default_method, static_cast<unsigned>(move),
+ Direction::FORWARD);
+ }
+ } else if (dev.model->asic_type == AsicType::GL842 ||
+ dev.model->asic_type == AsicType::GL843)
+ {
+ // do nothing
+ } else if (dev.model->asic_type == AsicType::GL845 ||
+ dev.model->asic_type == AsicType::GL846 ||
+ dev.model->asic_type == AsicType::GL847)
+ {
+ move = dev.model->y_offset_calib_white;
+ move = static_cast<float>((move * (dev.motor.base_ydpi / 4)) / MM_PER_INCH);
+ if (move > 20) {
+ scanner_move(dev, dev.model->default_method, static_cast<unsigned>(move),
+ Direction::FORWARD);
+ }
+ } else if (dev.model->asic_type == AsicType::GL124) {
+ gl124::move_to_calibration_area(&dev, sensor, regs);
+ }
- DBG(DBG_info, "channels %d y_size %f xres %d\n", channels, dev->model->y_size.value(),
- dev->settings.xres);
- unsigned size = static_cast<unsigned>(channels * 2 * dev->model->y_size * dev->settings.xres /
- MM_PER_INCH);
- /* 1 1 mm 1/inch inch/mm */
- std::vector<uint8_t> calibration_data(size);
- std::vector<uint8_t> all_data(size * 4, 1);
+ unsigned channels = 3;
+ unsigned resolution = sensor.shading_resolution;
+ const auto& calib_sensor = sanei_genesys_find_sensor(&dev, resolution, channels,
+ dev.settings.scan_method);
+
+ if (dev.model->asic_type == AsicType::GL845 ||
+ dev.model->asic_type == AsicType::GL846 ||
+ dev.model->asic_type == AsicType::GL847 ||
+ dev.model->asic_type == AsicType::GL124)
+ {
+ regs = dev.reg; // FIXME: apply this to all ASICs
+ }
+
+ unsigned yres = resolution;
+ if (dev.model->asic_type == AsicType::GL841) {
+ yres = dev.settings.yres; // FIXME: remove this
+ }
+
+ ScanSession session;
+ session.params.xres = resolution;
+ session.params.yres = yres;
+ session.params.startx = 0;
+ session.params.starty = 0;
+ session.params.pixels = dev.model->x_size_calib_mm * resolution / MM_PER_INCH;
+ session.params.lines = 1;
+ session.params.depth = 16;
+ session.params.channels = channels;
+ session.params.scan_method = dev.settings.scan_method;
+ session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
+ session.params.color_filter = dev.settings.color_filter;
+ session.params.flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA |
+ ScanFlag::SINGLE_LINE |
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET;
+ compute_session(&dev, session, calib_sensor);
+
+ dev.cmd_set->init_regs_for_scan_session(&dev, calib_sensor, &regs, session);
+
+ if (dev.model->asic_type == AsicType::GL841) {
+ dev.interface->write_registers(regs); // FIXME: remove this
+ }
+
+ std::uint16_t exp[3];
- dev->cmd_set->set_fe(dev, sensor, AFE_INIT);
+ if (dev.model->asic_type == AsicType::GL841) {
+ exp[0] = sensor.exposure.red;
+ exp[1] = sensor.exposure.green;
+ exp[2] = sensor.exposure.blue;
+ } else {
+ exp[0] = calib_sensor.exposure.red;
+ exp[1] = calib_sensor.exposure.green;
+ exp[2] = calib_sensor.exposure.blue;
+ }
+
+ std::uint16_t target = sensor.gain_white_ref * 256;
- dev->frontend.set_gain(0, 2);
- dev->frontend.set_gain(1, 2);
- dev->frontend.set_gain(2, 2); // TODO: ? was 2
- dev->frontend.set_offset(0, offset[0]);
- dev->frontend.set_offset(1, offset[0]);
- dev->frontend.set_offset(2, offset[0]);
+ std::uint16_t min_exposure = 500; // only gl841
+ std::uint16_t max_exposure = ((exp[0] + exp[1] + exp[2]) / 3) * 2; // only gl841
- for (i = 0; i < 4; i++) /* read 4 lines */
+ std::uint16_t top[3] = {};
+ std::uint16_t bottom[3] = {};
+
+ if (dev.model->asic_type == AsicType::GL845 ||
+ dev.model->asic_type == AsicType::GL846)
{
- if (i < 3) /* first 3 lines */
- {
- dev->frontend.set_offset(0, offset[i]);
- dev->frontend.set_offset(1, offset[i]);
- dev->frontend.set_offset(2, offset[i]);
+ bottom[0] = 29000;
+ bottom[1] = 29000;
+ bottom[2] = 29000;
+
+ top[0] = 41000;
+ top[1] = 51000;
+ top[2] = 51000;
+ } else if (dev.model->asic_type == AsicType::GL847) {
+ bottom[0] = 28000;
+ bottom[1] = 28000;
+ bottom[2] = 28000;
+
+ top[0] = 32000;
+ top[1] = 32000;
+ top[2] = 32000;
+ }
+
+ if (dev.model->asic_type == AsicType::GL845 ||
+ dev.model->asic_type == AsicType::GL846 ||
+ dev.model->asic_type == AsicType::GL847 ||
+ dev.model->asic_type == AsicType::GL124)
+ {
+ sanei_genesys_set_motor_power(regs, false);
+ }
+
+ bool acceptable = false;
+ for (unsigned i_test = 0; i_test < 100 && !acceptable; ++i_test) {
+ regs_set_exposure(dev.model->asic_type, regs, { exp[0], exp[1], exp[2] });
+
+ if (dev.model->asic_type == AsicType::GL841) {
+ // FIXME: remove
+ dev.interface->write_register(0x10, (exp[0] >> 8) & 0xff);
+ dev.interface->write_register(0x11, exp[0] & 0xff);
+ dev.interface->write_register(0x12, (exp[1] >> 8) & 0xff);
+ dev.interface->write_register(0x13, exp[1] & 0xff);
+ dev.interface->write_register(0x14, (exp[2] >> 8) & 0xff);
+ dev.interface->write_register(0x15, exp[2] & 0xff);
}
- if (i == 1) /* second line */
- {
- double applied_multi;
- double gain_white_ref;
+ dev.interface->write_registers(regs);
- if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
- dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
- {
- gain_white_ref = sensor.fau_gain_white_ref * 256;
+ dbg.log(DBG_info, "starting line reading");
+ dev.cmd_set->begin_scan(&dev, calib_sensor, &regs, true);
+
+ if (is_testing_mode()) {
+ dev.interface->test_checkpoint("led_calibration");
+ if (dev.model->asic_type == AsicType::GL841) {
+ scanner_stop_action(dev);
+ dev.cmd_set->move_back_home(&dev, true);
+ return { exp[0], exp[1], exp[2] };
+ } else if (dev.model->asic_type == AsicType::GL124) {
+ scanner_stop_action(dev);
+ return calib_sensor.exposure;
} else {
- gain_white_ref = sensor.gain_white_ref * 256;
+ scanner_stop_action(dev);
+ dev.cmd_set->move_back_home(&dev, true);
+ return calib_sensor.exposure;
}
+ }
- // white and black are defined downwards
-
- uint8_t gain0 = genesys_adjust_gain(&applied_multi,
- gain_white_ref / (white[0] - dark[0]),
- dev->frontend.get_gain(0));
- uint8_t gain1 = genesys_adjust_gain(&applied_multi,
- gain_white_ref / (white[1] - dark[1]),
- dev->frontend.get_gain(1));
- uint8_t gain2 = genesys_adjust_gain(&applied_multi,
- gain_white_ref / (white[2] - dark[2]),
- dev->frontend.get_gain(2));
- // FIXME: looks like overwritten data. Are the above calculations doing
- // anything at all?
- dev->frontend.set_gain(0, gain0);
- dev->frontend.set_gain(1, gain1);
- dev->frontend.set_gain(2, gain2);
- dev->frontend.set_gain(0, 2);
- dev->frontend.set_gain(1, 2);
- dev->frontend.set_gain(2, 2);
-
- dev->interface->write_fe_register(0x28, dev->frontend.get_gain(0));
- dev->interface->write_fe_register(0x29, dev->frontend.get_gain(1));
- dev->interface->write_fe_register(0x2a, dev->frontend.get_gain(2));
- }
+ auto image = read_unshuffled_image_from_scanner(&dev, session, session.output_line_bytes);
- if (i == 3) /* last line */
- {
- double x, y, rate;
+ scanner_stop_action(dev);
- for (j = 0; j < 3; j++)
- {
+ if (dbg_log_image_data()) {
+ char fn[30];
+ std::snprintf(fn, 30, "gl_led_%02d.tiff", i_test);
+ write_tiff_file(fn, image);
+ }
- x = static_cast<double>(dark[(i - 2) * 3 + j] -
- dark[(i - 1) * 3 + j]) * 254 / (offset[i - 1] / 2 -
- offset[i - 2] / 2);
- y = x - x * (offset[i - 1] / 2) / 254 - dark[(i - 1) * 3 + j];
- rate = (x - DARK_VALUE - y) * 254 / x + 0.5;
+ int avg[3];
+ for (unsigned ch = 0; ch < channels; ch++) {
+ avg[ch] = 0;
+ for (std::size_t x = 0; x < image.get_width(); x++) {
+ avg[ch] += image.get_raw_channel(x, 0, ch);
+ }
+ avg[ch] /= image.get_width();
+ }
- uint8_t curr_offset = static_cast<uint8_t>(rate);
+ dbg.vlog(DBG_info, "average: %d, %d, %d", avg[0], avg[1], avg[2]);
- if (curr_offset > 0x7f) {
- curr_offset = 0x7f;
- }
- curr_offset <<= 1;
- dev->frontend.set_offset(j, curr_offset);
- }
- }
- dev->interface->write_fe_register(0x20, dev->frontend.get_offset(0));
- dev->interface->write_fe_register(0x21, dev->frontend.get_offset(1));
- dev->interface->write_fe_register(0x22, dev->frontend.get_offset(2));
+ acceptable = true;
- DBG(DBG_info,
- "%s: doing scan: gain: %d/%d/%d, offset: %d/%d/%d\n", __func__,
- dev->frontend.get_gain(0),
- dev->frontend.get_gain(1),
- dev->frontend.get_gain(2),
- dev->frontend.get_offset(0),
- dev->frontend.get_offset(1),
- dev->frontend.get_offset(2));
+ if (dev.model->asic_type == AsicType::GL841) {
+ if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 ||
+ avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 ||
+ avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95)
+ {
+ acceptable = false;
+ }
+ // led exposure is not acceptable if white level is too low.
+ // ~80 hardcoded value for white level
+ if (avg[0] < 20000 || avg[1] < 20000 || avg[2] < 20000) {
+ acceptable = false;
+ }
- dev->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, false);
+ // for scanners using target value
+ if (target > 0) {
+ acceptable = true;
+ for (unsigned i = 0; i < 3; i++) {
+ // we accept +- 2% delta from target
+ if (std::abs(avg[i] - target) > target / 50) {
+ exp[i] = (exp[i] * target) / avg[i];
+ acceptable = false;
+ }
+ }
+ } else {
+ if (!acceptable) {
+ unsigned avga = (avg[0] + avg[1] + avg[2]) / 3;
+ exp[0] = (exp[0] * avga) / avg[0];
+ exp[1] = (exp[1] * avga) / avg[1];
+ exp[2] = (exp[2] * avga) / avg[2];
+ /* Keep the resulting exposures below this value. Too long exposure drives
+ the ccd into saturation. We may fix this by relying on the fact that
+ we get a striped scan without shading, by means of statistical calculation
+ */
+ unsigned avge = (exp[0] + exp[1] + exp[2]) / 3;
+
+ if (avge > max_exposure) {
+ exp[0] = (exp[0] * max_exposure) / avge;
+ exp[1] = (exp[1] * max_exposure) / avge;
+ exp[2] = (exp[2] * max_exposure) / avge;
+ }
+ if (avge < min_exposure) {
+ exp[0] = (exp[0] * min_exposure) / avge;
+ exp[1] = (exp[1] * min_exposure) / avge;
+ exp[2] = (exp[2] * min_exposure) / avge;
+ }
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("coarse_calibration");
- dev->cmd_set->end_scan(dev, &dev->calib_reg, true);
- return;
+ }
+ }
+ } else if (dev.model->asic_type == AsicType::GL845 ||
+ dev.model->asic_type == AsicType::GL846)
+ {
+ for (unsigned i = 0; i < 3; i++) {
+ if (avg[i] < bottom[i]) {
+ if (avg[i] != 0) {
+ exp[i] = (exp[i] * bottom[i]) / avg[i];
+ } else {
+ exp[i] *= 10;
+ }
+ acceptable = false;
+ }
+ if (avg[i] > top[i]) {
+ if (avg[i] != 0) {
+ exp[i] = (exp[i] * top[i]) / avg[i];
+ } else {
+ exp[i] *= 10;
+ }
+ acceptable = false;
+ }
+ }
+ } else if (dev.model->asic_type == AsicType::GL847) {
+ for (unsigned i = 0; i < 3; i++) {
+ if (avg[i] < bottom[i] || avg[i] > top[i]) {
+ auto target = (bottom[i] + top[i]) / 2;
+ if (avg[i] != 0) {
+ exp[i] = (exp[i] * target) / avg[i];
+ } else {
+ exp[i] *= 10;
+ }
+
+ acceptable = false;
+ }
+ }
+ } else if (dev.model->asic_type == AsicType::GL124) {
+ for (unsigned i = 0; i < 3; i++) {
+ // we accept +- 2% delta from target
+ if (std::abs(avg[i] - target) > target / 50) {
+ float prev_weight = 0.5;
+ if (avg[i] != 0) {
+ exp[i] = exp[i] * prev_weight + ((exp[i] * target) / avg[i]) * (1 - prev_weight);
+ } else {
+ exp[i] = exp[i] * prev_weight + (exp[i] * 10) * (1 - prev_weight);
+ }
+ acceptable = false;
+ }
+ }
}
+ }
- sanei_genesys_read_data_from_scanner(dev, calibration_data.data(), size);
- std::memcpy(all_data.data() + i * size, calibration_data.data(), size);
- if (i == 3) /* last line */
- {
- std::vector<uint8_t> all_data_8(size * 4 / 2);
- unsigned int count;
+ if (dev.model->asic_type == AsicType::GL845 ||
+ dev.model->asic_type == AsicType::GL846 ||
+ dev.model->asic_type == AsicType::GL847 ||
+ dev.model->asic_type == AsicType::GL124)
+ {
+ // set these values as final ones for scan
+ regs_set_exposure(dev.model->asic_type, dev.reg, { exp[0], exp[1], exp[2] });
+ }
- for (count = 0; count < static_cast<unsigned>(size * 4 / 2); count++) {
- all_data_8[count] = all_data[count * 2 + 1];
+ if (dev.model->asic_type == AsicType::GL841 ||
+ dev.model->asic_type == AsicType::GL842 ||
+ dev.model->asic_type == AsicType::GL843)
+ {
+ dev.cmd_set->move_back_home(&dev, true);
+ }
+
+ if (dev.model->asic_type == AsicType::GL845 ||
+ dev.model->asic_type == AsicType::GL846 ||
+ dev.model->asic_type == AsicType::GL847)
+ {
+ if (move > 20) {
+ dev.cmd_set->move_back_home(&dev, true);
}
- sanei_genesys_write_pnm_file("gl_coarse.pnm", all_data_8.data(), 8, channels, size / 6, 4);
- }
+ }
- dev->cmd_set->end_scan(dev, &dev->calib_reg, true);
+ dbg.vlog(DBG_info,"acceptable exposure: %d, %d, %d\n", exp[0], exp[1], exp[2]);
- if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS)
- {
- for (j = 0; j < 3; j++)
- {
- genesys_average_white(dev, sensor, 3, j, calibration_data.data(), size, &white_average);
- white[i * 3 + j] = white_average;
- dark[i * 3 + j] =
- genesys_average_black (dev, j, calibration_data.data(),
- black_pixels);
- DBG(DBG_info, "%s: white[%d]=%d, black[%d]=%d\n", __func__,
- i * 3 + j, white[i * 3 + j], i * 3 + j, dark[i * 3 + j]);
- }
- }
- else /* one color-component modes */
- {
- genesys_average_white(dev, sensor, 1, 0, calibration_data.data(), size, &white_average);
- white[i * 3 + 0] = white[i * 3 + 1] = white[i * 3 + 2] =
- white_average;
- dark[i * 3 + 0] = dark[i * 3 + 1] = dark[i * 3 + 2] =
- genesys_average_black (dev, 0, calibration_data.data(), black_pixels);
- }
- } /* for (i = 0; i < 4; i++) */
-
- DBG(DBG_info, "%s: final: gain: %d/%d/%d, offset: %d/%d/%d\n", __func__,
- dev->frontend.get_gain(0),
- dev->frontend.get_gain(1),
- dev->frontend.get_gain(2),
- dev->frontend.get_offset(0),
- dev->frontend.get_offset(1),
- dev->frontend.get_offset(2));
+ return { exp[0], exp[1], exp[2] };
+}
+
+void sanei_genesys_calculate_zmod(bool two_table,
+ uint32_t exposure_time,
+ const std::vector<uint16_t>& slope_table,
+ unsigned acceleration_steps,
+ unsigned move_steps,
+ unsigned buffer_acceleration_steps,
+ uint32_t* out_z1, uint32_t* out_z2)
+{
+ // acceleration total time
+ unsigned sum = std::accumulate(slope_table.begin(), slope_table.begin() + acceleration_steps,
+ 0, std::plus<unsigned>());
+
+ /* Z1MOD:
+ c = sum(slope_table; reg_stepno)
+ d = reg_fwdstep * <cruising speed>
+ Z1MOD = (c+d) % exposure_time
+ */
+ *out_z1 = (sum + buffer_acceleration_steps * slope_table[acceleration_steps - 1]) % exposure_time;
+
+ /* Z2MOD:
+ a = sum(slope_table; reg_stepno)
+ b = move_steps or 1 if 2 tables
+ Z1MOD = (a+b) % exposure_time
+ */
+ if (!two_table) {
+ sum = sum + (move_steps * slope_table[acceleration_steps - 1]);
+ } else {
+ sum = sum + slope_table[acceleration_steps - 1];
+ }
+ *out_z2 = sum % exposure_time;
}
/**
@@ -1614,22 +2311,41 @@ static void genesys_coarse_calibration(Genesys_Device* dev, Genesys_Sensor& sens
* @param dev scanner's device
*/
static void genesys_shading_calibration_impl(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& local_reg,
std::vector<std::uint16_t>& out_average_data,
bool is_dark, const std::string& log_filename_prefix)
{
DBG_HELPER(dbg);
+ if (dev->model->asic_type == AsicType::GL646) {
+ dev->cmd_set->init_regs_for_shading(dev, sensor, local_reg);
+ local_reg = dev->reg;
+ } else {
+ local_reg = dev->reg;
+ dev->cmd_set->init_regs_for_shading(dev, sensor, local_reg);
+ dev->interface->write_registers(local_reg);
+ }
+
debug_dump(DBG_info, dev->calib_session);
size_t size;
uint32_t pixels_per_line;
- uint8_t channels;
- /* end pixel - start pixel */
- pixels_per_line = dev->calib_pixels;
- channels = dev->calib_channels;
+ if (dev->model->asic_type == AsicType::GL842 ||
+ dev->model->asic_type == AsicType::GL843 ||
+ dev->model->model_id == ModelId::CANON_5600F)
+ {
+ pixels_per_line = dev->calib_session.output_pixels;
+ } else {
+ // BUG: this selects incorrect pixel number
+ pixels_per_line = dev->calib_session.params.pixels;
+ }
+ unsigned channels = dev->calib_session.params.channels;
- uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset;
+ // BUG: we are using wrong pixel number here
+ unsigned start_offset =
+ dev->calib_session.params.startx * sensor.full_resolution / dev->calib_session.params.xres;
+ unsigned out_pixels_per_line = pixels_per_line + start_offset;
// FIXME: we set this during both dark and white calibration. A cleaner approach should
// probably be used
@@ -1644,61 +2360,55 @@ static void genesys_shading_calibration_impl(Genesys_Device* dev, const Genesys_
}
// FIXME: the current calculation is likely incorrect on non-GL843 implementations,
- // but this needs checking
- if (dev->calib_total_bytes_to_read > 0) {
- size = dev->calib_total_bytes_to_read;
- } else if (dev->model->asic_type == AsicType::GL843) {
- size = channels * 2 * pixels_per_line * dev->calib_lines;
+ // but this needs checking. Note the extra line when computing size.
+ if (dev->model->asic_type == AsicType::GL842 ||
+ dev->model->asic_type == AsicType::GL843 ||
+ dev->model->model_id == ModelId::CANON_5600F)
+ {
+ size = dev->calib_session.output_total_bytes_raw;
} else {
- size = channels * 2 * pixels_per_line * (dev->calib_lines + 1);
+ size = channels * 2 * pixels_per_line * (dev->calib_session.params.lines + 1);
}
std::vector<uint16_t> calibration_data(size / 2);
- bool motor = true;
- if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE)
- {
- motor = false;
- }
-
// turn off motor and lamp power for flatbed scanners, but not for sheetfed scanners
// because they have a calibration sheet with a sufficient black strip
if (is_dark && !dev->model->is_sheetfed) {
- sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, false);
- sanei_genesys_set_motor_power(dev->calib_reg, motor);
+ sanei_genesys_set_lamp_power(dev, sensor, local_reg, false);
} else {
- sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, true);
- sanei_genesys_set_motor_power(dev->calib_reg, motor);
+ sanei_genesys_set_lamp_power(dev, sensor, local_reg, true);
}
+ sanei_genesys_set_motor_power(local_reg, true);
- dev->interface->write_registers(dev->calib_reg);
+ dev->interface->write_registers(local_reg);
if (is_dark) {
// wait some time to let lamp to get dark
dev->interface->sleep_ms(200);
- } else if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) {
+ } else if (has_flag(dev->model->flags, ModelFlag::DARK_CALIBRATION)) {
// make sure lamp is bright again
// FIXME: what about scanners that take a long time to warm the lamp?
dev->interface->sleep_ms(500);
}
bool start_motor = !is_dark;
- dev->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, start_motor);
+ dev->cmd_set->begin_scan(dev, sensor, &local_reg, start_motor);
if (is_testing_mode()) {
dev->interface->test_checkpoint(is_dark ? "dark_shading_calibration"
: "white_shading_calibration");
- dev->cmd_set->end_scan(dev, &dev->calib_reg, true);
+ dev->cmd_set->end_scan(dev, &local_reg, true);
return;
}
sanei_genesys_read_data_from_scanner(dev, reinterpret_cast<std::uint8_t*>(calibration_data.data()),
size);
- dev->cmd_set->end_scan(dev, &dev->calib_reg, true);
+ dev->cmd_set->end_scan(dev, &local_reg, true);
- if (dev->model->flags & GENESYS_FLAG_16BIT_DATA_INVERTED) {
+ if (has_flag(dev->model->flags, ModelFlag::SWAP_16BIT_DATA)) {
for (std::size_t i = 0; i < size / 2; ++i) {
auto value = calibration_data[i];
value = ((value >> 8) & 0xff) | ((value << 8) & 0xff00);
@@ -1706,30 +2416,29 @@ static void genesys_shading_calibration_impl(Genesys_Device* dev, const Genesys_
}
}
+ if (has_flag(dev->model->flags, ModelFlag::INVERT_PIXEL_DATA)) {
+ for (std::size_t i = 0; i < size / 2; ++i) {
+ calibration_data[i] = 0xffff - calibration_data[i];
+ }
+ }
+
std::fill(out_average_data.begin(),
- out_average_data.begin() + dev->calib_pixels_offset * channels, 0);
+ out_average_data.begin() + start_offset * channels, 0);
- compute_array_percentile_approx(out_average_data.data() + dev->calib_pixels_offset * channels,
+ compute_array_percentile_approx(out_average_data.data() +
+ start_offset * channels,
calibration_data.data(),
- dev->calib_lines, pixels_per_line * channels,
+ dev->calib_session.params.lines, pixels_per_line * channels,
0.5f);
- if (DBG_LEVEL >= DBG_data) {
- sanei_genesys_write_pnm_file16((log_filename_prefix + "_shading.pnm").c_str(),
- calibration_data.data(),
- channels, pixels_per_line, dev->calib_lines);
- sanei_genesys_write_pnm_file16((log_filename_prefix + "_average.pnm").c_str(),
- out_average_data.data(),
- channels, out_pixels_per_line, 1);
+ if (dbg_log_image_data()) {
+ write_tiff_file(log_filename_prefix + "_shading.tiff", calibration_data.data(), 16,
+ channels, pixels_per_line, dev->calib_session.params.lines);
+ write_tiff_file(log_filename_prefix + "_average.tiff", out_average_data.data(), 16,
+ channels, out_pixels_per_line, 1);
}
}
-
-static void genesys_dark_shading_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor)
-{
- DBG_HELPER(dbg);
- genesys_shading_calibration_impl(dev, sensor, dev->dark_average_data, true, "gl_black_");
-}
/*
* this function builds dummy dark calibration data so that we can
* compute shading coefficient in a clean way
@@ -1737,18 +2446,28 @@ static void genesys_dark_shading_calibration(Genesys_Device* dev, const Genesys_
* can be computed from previous calibration data (when doing offset
* calibration ?)
*/
-static void genesys_dummy_dark_shading(Genesys_Device* dev, const Genesys_Sensor& sensor)
+static void genesys_dark_shading_by_dummy_pixel(Genesys_Device* dev, const Genesys_Sensor& sensor)
{
DBG_HELPER(dbg);
uint32_t pixels_per_line;
- uint8_t channels;
uint32_t skip, xend;
int dummy1, dummy2, dummy3; /* dummy black average per channel */
- pixels_per_line = dev->calib_pixels;
- channels = dev->calib_channels;
+ if (dev->model->asic_type == AsicType::GL842 ||
+ dev->model->asic_type == AsicType::GL843)
+ {
+ pixels_per_line = dev->calib_session.output_pixels;
+ } else {
+ pixels_per_line = dev->calib_session.params.pixels;
+ }
+
+ unsigned channels = dev->calib_session.params.channels;
+
+ // BUG: we are using wrong pixel number here
+ unsigned start_offset =
+ dev->calib_session.params.startx * sensor.full_resolution / dev->calib_session.params.xres;
- uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset;
+ unsigned out_pixels_per_line = pixels_per_line + start_offset;
dev->average_size = channels * out_pixels_per_line;
dev->dark_average_data.clear();
@@ -1756,8 +2475,7 @@ static void genesys_dummy_dark_shading(Genesys_Device* dev, const Genesys_Sensor
/* we average values on 'the left' where CCD pixels are under casing and
give darkest values. We then use these as dummy dark calibration */
- if (dev->settings.xres <= sensor.optical_res / 2)
- {
+ if (dev->settings.xres <= sensor.full_resolution / 2) {
skip = 4;
xend = 36;
}
@@ -1807,17 +2525,22 @@ static void genesys_dummy_dark_shading(Genesys_Device* dev, const Genesys_Sensor
}
}
+static void genesys_dark_shading_by_constant(Genesys_Device& dev)
+{
+ dev.dark_average_data.clear();
+ dev.dark_average_data.resize(dev.average_size, 0x0101);
+}
static void genesys_repark_sensor_before_shading(Genesys_Device* dev)
{
DBG_HELPER(dbg);
- if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK) {
+ if (has_flag(dev->model->flags, ModelFlag::SHADING_REPARK)) {
dev->cmd_set->move_back_home(dev, true);
if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
- dev->cmd_set->move_to_ta(dev);
+ scanner_move_to_ta(*dev);
}
}
}
@@ -1825,34 +2548,153 @@ static void genesys_repark_sensor_before_shading(Genesys_Device* dev)
static void genesys_repark_sensor_after_white_shading(Genesys_Device* dev)
{
DBG_HELPER(dbg);
- if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK) {
+ if (has_flag(dev->model->flags, ModelFlag::SHADING_REPARK)) {
dev->cmd_set->move_back_home(dev, true);
}
}
-static void genesys_white_shading_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor)
+static void genesys_host_shading_calibration_impl(Genesys_Device& dev, const Genesys_Sensor& sensor,
+ std::vector<std::uint16_t>& out_average_data,
+ bool is_dark,
+ const std::string& log_filename_prefix)
{
DBG_HELPER(dbg);
- genesys_shading_calibration_impl(dev, sensor, dev->white_average_data, false, "gl_white_");
+
+ if (is_dark && dev.settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) {
+ // FIXME: dark shading currently not supported on infrared transparency scans
+ return;
+ }
+
+ auto local_reg = dev.reg;
+ dev.cmd_set->init_regs_for_shading(&dev, sensor, local_reg);
+
+ auto& session = dev.calib_session;
+ debug_dump(DBG_info, session);
+
+ // turn off motor and lamp power for flatbed scanners, but not for sheetfed scanners
+ // because they have a calibration sheet with a sufficient black strip
+ if (is_dark && !dev.model->is_sheetfed) {
+ sanei_genesys_set_lamp_power(&dev, sensor, local_reg, false);
+ } else {
+ sanei_genesys_set_lamp_power(&dev, sensor, local_reg, true);
+ }
+ sanei_genesys_set_motor_power(local_reg, true);
+
+ dev.interface->write_registers(local_reg);
+
+ if (is_dark) {
+ // wait some time to let lamp to get dark
+ dev.interface->sleep_ms(200);
+ } else if (has_flag(dev.model->flags, ModelFlag::DARK_CALIBRATION)) {
+ // make sure lamp is bright again
+ // FIXME: what about scanners that take a long time to warm the lamp?
+ dev.interface->sleep_ms(500);
+ }
+
+ bool start_motor = !is_dark;
+ dev.cmd_set->begin_scan(&dev, sensor, &local_reg, start_motor);
+
+ if (is_testing_mode()) {
+ dev.interface->test_checkpoint(is_dark ? "host_dark_shading_calibration"
+ : "host_white_shading_calibration");
+ dev.cmd_set->end_scan(&dev, &local_reg, true);
+ return;
+ }
+
+ Image image = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes_raw);
+ scanner_stop_action(dev);
+
+ auto start_offset = session.params.startx;
+ auto out_pixels_per_line = start_offset + session.output_pixels;
+
+ // FIXME: we set this during both dark and white calibration. A cleaner approach should
+ // probably be used
+ dev.average_size = session.params.channels * out_pixels_per_line;
+
+ out_average_data.clear();
+ out_average_data.resize(dev.average_size);
+
+ std::fill(out_average_data.begin(),
+ out_average_data.begin() + start_offset * session.params.channels, 0);
+
+ compute_array_percentile_approx(out_average_data.data() +
+ start_offset * session.params.channels,
+ reinterpret_cast<std::uint16_t*>(image.get_row_ptr(0)),
+ session.params.lines,
+ session.output_pixels * session.params.channels,
+ 0.5f);
+
+ if (dbg_log_image_data()) {
+ write_tiff_file(log_filename_prefix + "_host_shading.tiff", image);
+ write_tiff_file(log_filename_prefix + "_host_average.tiff", out_average_data.data(), 16,
+ session.params.channels, out_pixels_per_line, 1);
+ }
+}
+
+static void genesys_dark_shading_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& local_reg)
+{
+ DBG_HELPER(dbg);
+ if (has_flag(dev->model->flags, ModelFlag::HOST_SIDE_CALIBRATION_COMPLETE_SCAN)) {
+ genesys_host_shading_calibration_impl(*dev, sensor, dev->dark_average_data, true,
+ "gl_black");
+ } else {
+ genesys_shading_calibration_impl(dev, sensor, local_reg, dev->dark_average_data, true,
+ "gl_black");
+ }
+}
+
+static void genesys_white_shading_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& local_reg)
+{
+ DBG_HELPER(dbg);
+ if (has_flag(dev->model->flags, ModelFlag::HOST_SIDE_CALIBRATION_COMPLETE_SCAN)) {
+ genesys_host_shading_calibration_impl(*dev, sensor, dev->white_average_data, false,
+ "gl_white");
+ } else {
+ genesys_shading_calibration_impl(dev, sensor, local_reg, dev->white_average_data, false,
+ "gl_white");
+ }
}
// This calibration uses a scan over the calibration target, comprising a black and a white strip.
// (So the motor must be on.)
static void genesys_dark_white_shading_calibration(Genesys_Device* dev,
- const Genesys_Sensor& sensor)
+ const Genesys_Sensor& sensor,
+ Genesys_Register_Set& local_reg)
{
- DBG_HELPER_ARGS(dbg, "lines = %zu", dev->calib_lines);
+ DBG_HELPER(dbg);
+
+ if (dev->model->asic_type == AsicType::GL646) {
+ dev->cmd_set->init_regs_for_shading(dev, sensor, local_reg);
+ local_reg = dev->reg;
+ } else {
+ local_reg = dev->reg;
+ dev->cmd_set->init_regs_for_shading(dev, sensor, local_reg);
+ dev->interface->write_registers(local_reg);
+ }
+
size_t size;
uint32_t pixels_per_line;
- uint8_t channels;
unsigned int x;
uint32_t dark, white, dark_sum, white_sum, dark_count, white_count, col,
dif;
- pixels_per_line = dev->calib_pixels;
- channels = dev->calib_channels;
+ if (dev->model->asic_type == AsicType::GL842 ||
+ dev->model->asic_type == AsicType::GL843)
+ {
+ pixels_per_line = dev->calib_session.output_pixels;
+ } else {
+ pixels_per_line = dev->calib_session.params.pixels;
+ }
- uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset;
+ unsigned channels = dev->calib_session.params.channels;
+
+ // BUG: we are using wrong pixel number here
+ unsigned start_offset =
+ dev->calib_session.params.startx * sensor.full_resolution / dev->calib_session.params.xres;
+
+ unsigned out_pixels_per_line = pixels_per_line + start_offset;
dev->average_size = channels * out_pixels_per_line;
@@ -1862,68 +2704,65 @@ static void genesys_dark_white_shading_calibration(Genesys_Device* dev,
dev->dark_average_data.clear();
dev->dark_average_data.resize(dev->average_size);
- if (dev->calib_total_bytes_to_read > 0)
- size = dev->calib_total_bytes_to_read;
- else
- size = channels * 2 * pixels_per_line * dev->calib_lines;
-
- std::vector<uint8_t> calibration_data(size);
-
- bool motor = true;
- if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE)
+ if (dev->model->asic_type == AsicType::GL842 ||
+ dev->model->asic_type == AsicType::GL843)
{
- motor = false;
+ size = dev->calib_session.output_total_bytes_raw;
+ } else {
+ // FIXME: on GL841 this is different than dev->calib_session.output_total_bytes_raw,
+ // needs checking
+ size = channels * 2 * pixels_per_line * dev->calib_session.params.lines;
}
+ std::vector<uint8_t> calibration_data(size);
+
// turn on motor and lamp power
- sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, true);
- sanei_genesys_set_motor_power(dev->calib_reg, motor);
+ sanei_genesys_set_lamp_power(dev, sensor, local_reg, true);
+ sanei_genesys_set_motor_power(local_reg, true);
- dev->interface->write_registers(dev->calib_reg);
+ dev->interface->write_registers(local_reg);
- dev->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, false);
+ dev->cmd_set->begin_scan(dev, sensor, &local_reg, false);
if (is_testing_mode()) {
dev->interface->test_checkpoint("dark_white_shading_calibration");
- dev->cmd_set->end_scan(dev, &dev->calib_reg, true);
+ dev->cmd_set->end_scan(dev, &local_reg, true);
return;
}
sanei_genesys_read_data_from_scanner(dev, calibration_data.data(), size);
- dev->cmd_set->end_scan(dev, &dev->calib_reg, true);
+ dev->cmd_set->end_scan(dev, &local_reg, true);
- if (DBG_LEVEL >= DBG_data)
- {
- if (dev->model->is_cis)
- {
- sanei_genesys_write_pnm_file("gl_black_white_shading.pnm", calibration_data.data(),
- 16, 1, pixels_per_line*channels,
- dev->calib_lines);
- }
- else
- {
- sanei_genesys_write_pnm_file("gl_black_white_shading.pnm", calibration_data.data(),
- 16, channels, pixels_per_line,
- dev->calib_lines);
+ if (dbg_log_image_data()) {
+ if (dev->model->is_cis) {
+ write_tiff_file("gl_black_white_shading.tiff", calibration_data.data(),
+ 16, 1, pixels_per_line*channels,
+ dev->calib_session.params.lines);
+ } else {
+ write_tiff_file("gl_black_white_shading.tiff", calibration_data.data(),
+ 16, channels, pixels_per_line,
+ dev->calib_session.params.lines);
}
}
std::fill(dev->dark_average_data.begin(),
- dev->dark_average_data.begin() + dev->calib_pixels_offset * channels, 0);
+ dev->dark_average_data.begin() + start_offset * channels, 0);
std::fill(dev->white_average_data.begin(),
- dev->white_average_data.begin() + dev->calib_pixels_offset * channels, 0);
+ dev->white_average_data.begin() + start_offset * channels, 0);
- uint16_t* average_white = dev->white_average_data.data() + dev->calib_pixels_offset * channels;
- uint16_t* average_dark = dev->dark_average_data.data() + dev->calib_pixels_offset * channels;
+ uint16_t* average_white = dev->white_average_data.data() +
+ start_offset * channels;
+ uint16_t* average_dark = dev->dark_average_data.data() +
+ start_offset * channels;
for (x = 0; x < pixels_per_line * channels; x++)
{
dark = 0xffff;
white = 0;
- for (std::size_t y = 0; y < dev->calib_lines; y++)
+ for (std::size_t y = 0; y < dev->calib_session.params.lines; y++)
{
col = calibration_data[(x + y * pixels_per_line * channels) * 2];
col |=
@@ -1947,7 +2786,7 @@ static void genesys_dark_white_shading_calibration(Genesys_Device* dev,
white_count = 0;
white_sum = 0;
- for (std::size_t y = 0; y < dev->calib_lines; y++)
+ for (std::size_t y = 0; y < dev->calib_session.params.lines; y++)
{
col = calibration_data[(x + y * pixels_per_line * channels) * 2];
col |=
@@ -1974,11 +2813,11 @@ static void genesys_dark_white_shading_calibration(Genesys_Device* dev,
*average_white++ = white_sum;
}
- if (DBG_LEVEL >= DBG_data) {
- sanei_genesys_write_pnm_file16("gl_white_average.pnm", dev->white_average_data.data(),
- channels, out_pixels_per_line, 1);
- sanei_genesys_write_pnm_file16("gl_dark_average.pnm", dev->dark_average_data.data(),
- channels, out_pixels_per_line, 1);
+ if (dbg_log_image_data()) {
+ write_tiff_file("gl_white_average.tiff", dev->white_average_data.data(), 16, channels,
+ out_pixels_per_line, 1);
+ write_tiff_file("gl_dark_average.tiff", dev->dark_average_data.data(), 16, channels,
+ out_pixels_per_line, 1);
}
}
@@ -2085,13 +2924,12 @@ compute_averaged_planar (Genesys_Device * dev, const Genesys_Sensor& sensor,
*/
res = dev->settings.xres;
- if (sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres) > 1)
- {
+ if (sensor.full_resolution > sensor.get_optical_resolution()) {
res *= 2;
}
- /* this should be evenly dividable */
- basepixels = sensor.optical_res / res;
+ // this should be evenly dividable
+ basepixels = sensor.full_resolution / res;
/* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */
if (basepixels < 1)
@@ -2376,9 +3214,10 @@ compute_shifted_coefficients (Genesys_Device * dev,
auto cmat = color_order_to_cmat(color_order);
x = dev->settings.xres;
- if (sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres) > 1)
- x *= 2; /* scanner is using half-ccd mode */
- basepixels = sensor.optical_res / x; /*this should be evenly dividable */
+ if (sensor.full_resolution > sensor.get_optical_resolution()) {
+ x *= 2; // scanner is using half-ccd mode
+ }
+ basepixels = sensor.full_resolution / x; // this should be evenly dividable
/* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */
if (basepixels < 1)
@@ -2451,19 +3290,30 @@ static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_
{
DBG_HELPER(dbg);
- if (dev->model->flags & GENESYS_FLAG_CALIBRATION_HOST_SIDE) {
+ if (sensor.use_host_side_calib) {
return;
}
uint32_t pixels_per_line;
- uint8_t channels;
int o;
unsigned int length; /**> number of shading calibration data words */
unsigned int factor;
unsigned int coeff, target_code, words_per_color = 0;
- pixels_per_line = dev->calib_pixels + dev->calib_pixels_offset;
- channels = dev->calib_channels;
+
+ // BUG: we are using wrong pixel number here
+ unsigned start_offset =
+ dev->calib_session.params.startx * sensor.full_resolution / dev->calib_session.params.xres;
+
+ if (dev->model->asic_type == AsicType::GL842 ||
+ dev->model->asic_type == AsicType::GL843)
+ {
+ pixels_per_line = dev->calib_session.output_pixels + start_offset;
+ } else {
+ pixels_per_line = dev->calib_session.params.pixels + start_offset;
+ }
+
+ unsigned channels = dev->calib_session.params.channels;
/* we always build data for three channels, even for gray
* we make the shading data such that each color channel data line is contiguous
@@ -2504,25 +3354,27 @@ static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_
// contains 16bit words in little endian
std::vector<uint8_t> shading_data(length, 0);
+ if (!dev->calib_session.computed) {
+ genesys_send_offset_and_shading(dev, sensor, shading_data.data(), length);
+ return;
+ }
+
/* TARGET/(Wn-Dn) = white gain -> ~1.xxx then it is multiplied by 0x2000
or 0x4000 to give an integer
Wn = white average for column n
Dn = dark average for column n
*/
- if (get_registers_gain4_bit(dev->model->asic_type, dev->calib_reg)) {
+ if (get_registers_gain4_bit(dev->model->asic_type, dev->reg)) {
coeff = 0x4000;
} else {
coeff = 0x2000;
}
/* compute avg factor */
- if(dev->settings.xres>sensor.optical_res)
- {
- factor=1;
- }
- else
- {
- factor=sensor.optical_res/dev->settings.xres;
+ if (dev->settings.xres > sensor.full_resolution) {
+ factor = 1;
+ } else {
+ factor = sensor.full_resolution / dev->settings.xres;
}
/* for GL646, shading data is planar if REG_0x01_FASTMOD is set and
@@ -2536,6 +3388,7 @@ static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_
switch (dev->model->sensor_id)
{
case SensorId::CCD_XP300:
+ case SensorId::CCD_DOCKETPORT_487:
case SensorId::CCD_ROADWARRIOR:
case SensorId::CCD_DP665:
case SensorId::CCD_DP685:
@@ -2570,10 +3423,9 @@ static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_
case SensorId::CCD_HP2300:
target_code = 0xdc00;
o = 2;
- if(dev->settings.xres<=sensor.optical_res/2)
- {
- o = o - sensor.dummy_pixel / 2;
- }
+ if (dev->settings.xres <= sensor.full_resolution / 2) {
+ o = o - sensor.dummy_pixel / 2;
+ }
compute_coefficients (dev,
shading_data.data(),
pixels_per_line,
@@ -2586,7 +3438,7 @@ static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_
case SensorId::CCD_5345:
target_code = 0xe000;
o = 4;
- if(dev->settings.xres<=sensor.optical_res/2)
+ if(dev->settings.xres<=sensor.full_resolution/2)
{
o = o - sensor.dummy_pixel;
}
@@ -2633,9 +3485,12 @@ static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_
case SensorId::CCD_CANON_4400F:
case SensorId::CCD_CANON_8400F:
case SensorId::CCD_CANON_8600F:
+ case SensorId::CCD_PLUSTEK_OPTICFILM_7200:
case SensorId::CCD_PLUSTEK_OPTICFILM_7200I:
case SensorId::CCD_PLUSTEK_OPTICFILM_7300:
+ case SensorId::CCD_PLUSTEK_OPTICFILM_7400:
case SensorId::CCD_PLUSTEK_OPTICFILM_7500I:
+ case SensorId::CCD_PLUSTEK_OPTICFILM_8200I:
target_code = 0xe000;
o = 0;
compute_coefficients (dev,
@@ -2654,6 +3509,7 @@ static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_
case SensorId::CIS_CANON_LIDE_120:
case SensorId::CIS_CANON_LIDE_210:
case SensorId::CIS_CANON_LIDE_220:
+ case SensorId::CCD_CANON_5600F:
/* TODO store this in a data struct so we avoid
* growing this switch */
switch(dev->model->sensor_id)
@@ -2684,6 +3540,8 @@ static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_
target_code);
break;
case SensorId::CIS_CANON_LIDE_35:
+ case SensorId::CIS_CANON_LIDE_60:
+ case SensorId::CIS_CANON_LIDE_90:
compute_averaged_planar (dev, sensor,
shading_data.data(),
pixels_per_line,
@@ -2756,9 +3614,8 @@ genesys_restore_calibration(Genesys_Device * dev, Genesys_Sensor& sensor)
/* we don't restore the gamma fields */
sensor.exposure = cache.sensor.exposure;
+ dev->calib_session = cache.session;
dev->average_size = cache.average_size;
- dev->calib_pixels = cache.calib_pixels;
- dev->calib_channels = cache.calib_channels;
dev->dark_average_data = cache.dark_average_data;
dev->white_average_data = cache.white_average_data;
@@ -2812,8 +3669,7 @@ static void genesys_save_calibration(Genesys_Device* dev, const Genesys_Sensor&
found_cache_it->frontend = dev->frontend;
found_cache_it->sensor = sensor;
- found_cache_it->calib_pixels = dev->calib_pixels;
- found_cache_it->calib_channels = dev->calib_channels;
+ found_cache_it->session = dev->calib_session;
#ifdef HAVE_SYS_TIME_H
gettimeofday(&time, nullptr);
@@ -2821,20 +3677,13 @@ static void genesys_save_calibration(Genesys_Device* dev, const Genesys_Sensor&
#endif
}
-/**
- * does the calibration process for a flatbed scanner
- * - offset calibration
- * - gain calibration
- * - shading calibration
- * @param dev device to calibrate
- */
static void genesys_flatbed_calibration(Genesys_Device* dev, Genesys_Sensor& sensor)
{
DBG_HELPER(dbg);
- uint32_t pixels_per_line;
+ uint32_t pixels_per_line;
- unsigned coarse_res = sensor.optical_res;
- if (dev->settings.yres <= sensor.optical_res / 2) {
+ unsigned coarse_res = sensor.full_resolution;
+ if (dev->settings.yres <= sensor.full_resolution / 2) {
coarse_res /= 2;
}
@@ -2848,35 +3697,29 @@ static void genesys_flatbed_calibration(Genesys_Device* dev, Genesys_Sensor& sen
coarse_res = 1200;
}
- /* do offset calibration if needed */
- if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION)
- {
+ auto local_reg = dev->initial_regs;
+
+ if (!has_flag(dev->model->flags, ModelFlag::DISABLE_ADC_CALIBRATION)) {
+ // do ADC calibration first.
dev->interface->record_progress_message("offset_calibration");
- dev->cmd_set->offset_calibration(dev, sensor, dev->calib_reg);
+ dev->cmd_set->offset_calibration(dev, sensor, local_reg);
- /* since all the registers are set up correctly, just use them */
dev->interface->record_progress_message("coarse_gain_calibration");
- dev->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, coarse_res);
- } else {
- /* since we have 2 gain calibration proc, skip second if first one was
- used. */
- dev->interface->record_progress_message("init_regs_for_coarse_calibration");
- dev->cmd_set->init_regs_for_coarse_calibration(dev, sensor, dev->calib_reg);
-
- dev->interface->record_progress_message("genesys_coarse_calibration");
- genesys_coarse_calibration(dev, sensor);
+ dev->cmd_set->coarse_gain_calibration(dev, sensor, local_reg, coarse_res);
}
- if (dev->model->is_cis)
+ if (dev->model->is_cis &&
+ !has_flag(dev->model->flags, ModelFlag::DISABLE_EXPOSURE_CALIBRATION))
{
- /* the afe now sends valid data for doing led calibration */
+ // ADC now sends correct data, we can configure the exposure for the LEDs
dev->interface->record_progress_message("led_calibration");
switch (dev->model->asic_type) {
case AsicType::GL124:
+ case AsicType::GL841:
case AsicType::GL845:
case AsicType::GL846:
case AsicType::GL847: {
- auto calib_exposure = dev->cmd_set->led_calibration(dev, sensor, dev->calib_reg);
+ auto calib_exposure = dev->cmd_set->led_calibration(dev, sensor, local_reg);
for (auto& sensor_update :
sanei_genesys_find_sensors_all_for_write(dev, sensor.method)) {
sensor_update.get().exposure = calib_exposure;
@@ -2885,80 +3728,66 @@ static void genesys_flatbed_calibration(Genesys_Device* dev, Genesys_Sensor& sen
break;
}
default: {
- sensor.exposure = dev->cmd_set->led_calibration(dev, sensor, dev->calib_reg);
+ sensor.exposure = dev->cmd_set->led_calibration(dev, sensor, local_reg);
}
}
-
- /* calibrate afe again to match new exposure */
- if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) {
+ if (!has_flag(dev->model->flags, ModelFlag::DISABLE_ADC_CALIBRATION)) {
+ // recalibrate ADC again for the new LED exposure
dev->interface->record_progress_message("offset_calibration");
- dev->cmd_set->offset_calibration(dev, sensor, dev->calib_reg);
-
- // since all the registers are set up correctly, just use them
+ dev->cmd_set->offset_calibration(dev, sensor, local_reg);
dev->interface->record_progress_message("coarse_gain_calibration");
- dev->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, coarse_res);
- } else {
- // since we have 2 gain calibration proc, skip second if first one was used
- dev->interface->record_progress_message("init_regs_for_coarse_calibration");
- dev->cmd_set->init_regs_for_coarse_calibration(dev, sensor, dev->calib_reg);
-
- dev->interface->record_progress_message("genesys_coarse_calibration");
- genesys_coarse_calibration(dev, sensor);
+ dev->cmd_set->coarse_gain_calibration(dev, sensor, local_reg, coarse_res);
}
}
/* we always use sensor pixel number when the ASIC can't handle multi-segments sensor */
- if (!(dev->model->flags & GENESYS_FLAG_SIS_SENSOR))
- {
+ if (!has_flag(dev->model->flags, ModelFlag::SIS_SENSOR)) {
pixels_per_line = static_cast<std::uint32_t>((dev->model->x_size * dev->settings.xres) /
MM_PER_INCH);
- }
- else
- {
- pixels_per_line = sensor.sensor_pixels;
+ } else {
+ pixels_per_line = static_cast<std::uint32_t>((dev->model->x_size_calib_mm * dev->settings.xres)
+ / MM_PER_INCH);
}
// send default shading data
dev->interface->record_progress_message("sanei_genesys_init_shading_data");
sanei_genesys_init_shading_data(dev, sensor, pixels_per_line);
- if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
- dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
- {
- dev->cmd_set->move_to_ta(dev);
- }
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ scanner_move_to_ta(*dev);
+ }
// shading calibration
- if (dev->model->flags & GENESYS_FLAG_DARK_WHITE_CALIBRATION) {
- dev->interface->record_progress_message("init_regs_for_shading");
- dev->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg);
-
- dev->interface->record_progress_message("genesys_dark_white_shading_calibration");
- genesys_dark_white_shading_calibration(dev, sensor);
- } else {
- DBG(DBG_proc, "%s : genesys_dark_shading_calibration dev->calib_reg ", __func__);
- debug_dump(DBG_proc, dev->calib_reg);
-
- if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) {
- dev->interface->record_progress_message("init_regs_for_shading");
- dev->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg);
+ if (!has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION)) {
+ if (has_flag(dev->model->flags, ModelFlag::DARK_WHITE_CALIBRATION)) {
+ dev->interface->record_progress_message("genesys_dark_white_shading_calibration");
+ genesys_dark_white_shading_calibration(dev, sensor, local_reg);
+ } else {
+ DBG(DBG_proc, "%s : genesys_dark_shading_calibration local_reg ", __func__);
+ debug_dump(DBG_proc, local_reg);
- dev->interface->record_progress_message("genesys_dark_shading_calibration");
- genesys_dark_shading_calibration(dev, sensor);
- genesys_repark_sensor_before_shading(dev);
- }
+ if (has_flag(dev->model->flags, ModelFlag::DARK_CALIBRATION)) {
+ dev->interface->record_progress_message("genesys_dark_shading_calibration");
+ genesys_dark_shading_calibration(dev, sensor, local_reg);
+ genesys_repark_sensor_before_shading(dev);
+ }
- dev->interface->record_progress_message("init_regs_for_shading2");
- dev->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg);
+ dev->interface->record_progress_message("genesys_white_shading_calibration");
+ genesys_white_shading_calibration(dev, sensor, local_reg);
- dev->interface->record_progress_message("genesys_white_shading_calibration");
- genesys_white_shading_calibration(dev, sensor);
- genesys_repark_sensor_after_white_shading(dev);
+ genesys_repark_sensor_after_white_shading(dev);
- if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) {
- genesys_dummy_dark_shading(dev, sensor);
+ if (!has_flag(dev->model->flags, ModelFlag::DARK_CALIBRATION)) {
+ if (has_flag(dev->model->flags, ModelFlag::USE_CONSTANT_FOR_DARK_CALIBRATION)) {
+ genesys_dark_shading_by_constant(*dev);
+ } else {
+ genesys_dark_shading_by_dummy_pixel(dev, sensor);
+ }
+ }
}
}
@@ -2982,68 +3811,62 @@ static void genesys_sheetfed_calibration(Genesys_Device* dev, Genesys_Sensor& se
DBG_HELPER(dbg);
bool forward = true;
+ auto local_reg = dev->initial_regs;
+
// first step, load document
dev->cmd_set->load_document(dev);
- /* led, offset and gain calibration are influenced by scan
- * settings. So we set it to sensor resolution */
- dev->settings.xres = sensor.optical_res;
- /* XP200 needs to calibrate a full and half sensor's resolution */
- if (dev->model->sensor_id == SensorId::CIS_XP200 &&
- dev->settings.xres <= sensor.optical_res / 2)
- {
- dev->settings.xres /= 2;
- }
+ unsigned coarse_res = sensor.full_resolution;
/* the afe needs to sends valid data even before calibration */
/* go to a white area */
try {
- dev->cmd_set->search_strip(dev, sensor, forward, false);
+ scanner_search_strip(*dev, forward, false);
} catch (...) {
catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); });
throw;
}
- if (dev->model->is_cis)
- {
- dev->cmd_set->led_calibration(dev, sensor, dev->calib_reg);
+ if (!has_flag(dev->model->flags, ModelFlag::DISABLE_ADC_CALIBRATION)) {
+ // do ADC calibration first.
+ dev->interface->record_progress_message("offset_calibration");
+ dev->cmd_set->offset_calibration(dev, sensor, local_reg);
+
+ dev->interface->record_progress_message("coarse_gain_calibration");
+ dev->cmd_set->coarse_gain_calibration(dev, sensor, local_reg, coarse_res);
}
- /* calibrate afe */
- if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION)
+ if (dev->model->is_cis &&
+ !has_flag(dev->model->flags, ModelFlag::DISABLE_EXPOSURE_CALIBRATION))
{
- dev->cmd_set->offset_calibration(dev, sensor, dev->calib_reg);
-
- /* since all the registers are set up correctly, just use them */
+ // ADC now sends correct data, we can configure the exposure for the LEDs
+ dev->interface->record_progress_message("led_calibration");
+ dev->cmd_set->led_calibration(dev, sensor, local_reg);
- dev->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, sensor.optical_res);
- }
- else
- /* since we have 2 gain calibration proc, skip second if first one was
- used. */
- {
- dev->cmd_set->init_regs_for_coarse_calibration(dev, sensor, dev->calib_reg);
+ if (!has_flag(dev->model->flags, ModelFlag::DISABLE_ADC_CALIBRATION)) {
+ // recalibrate ADC again for the new LED exposure
+ dev->interface->record_progress_message("offset_calibration");
+ dev->cmd_set->offset_calibration(dev, sensor, local_reg);
- genesys_coarse_calibration(dev, sensor);
+ dev->interface->record_progress_message("coarse_gain_calibration");
+ dev->cmd_set->coarse_gain_calibration(dev, sensor, local_reg, coarse_res);
+ }
}
/* search for a full width black strip and then do a 16 bit scan to
* gather black shading data */
- if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)
- {
- /* seek black/white reverse/forward */
+ if (has_flag(dev->model->flags, ModelFlag::DARK_CALIBRATION)) {
+ // seek black/white reverse/forward
try {
- dev->cmd_set->search_strip(dev, sensor, forward, true);
+ scanner_search_strip(*dev, forward, true);
} catch (...) {
catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); });
throw;
}
- dev->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg);
-
try {
- genesys_dark_shading_calibration(dev, sensor);
+ genesys_dark_shading_calibration(dev, sensor, local_reg);
} catch (...) {
catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); });
throw;
@@ -3054,7 +3877,7 @@ static void genesys_sheetfed_calibration(Genesys_Device* dev, Genesys_Sensor& se
/* go to a white area */
try {
- dev->cmd_set->search_strip(dev, sensor, forward, false);
+ scanner_search_strip(*dev, forward, false);
} catch (...) {
catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); });
throw;
@@ -3062,10 +3885,8 @@ static void genesys_sheetfed_calibration(Genesys_Device* dev, Genesys_Sensor& se
genesys_repark_sensor_before_shading(dev);
- dev->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg);
-
try {
- genesys_white_shading_calibration(dev, sensor);
+ genesys_white_shading_calibration(dev, sensor, local_reg);
genesys_repark_sensor_after_white_shading(dev);
} catch (...) {
catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); });
@@ -3073,17 +3894,9 @@ static void genesys_sheetfed_calibration(Genesys_Device* dev, Genesys_Sensor& se
}
// in case we haven't black shading data, build it from black pixels of white calibration
- // FIXME: shouldn't we use genesys_dummy_dark_shading() ?
- if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) {
- dev->dark_average_data.clear();
- dev->dark_average_data.resize(dev->average_size, 0x0f0f);
- /* XXX STEF XXX
- * with black point in white shading, build an average black
- * pixel and use it to fill the dark_average
- * dev->calib_pixels
- (sensor.sensor_pixels * dev->settings.xres) / sensor.optical_res,
- dev->calib_lines,
- */
+ // FIXME: shouldn't we use genesys_dark_shading_by_dummy_pixel() ?
+ if (!has_flag(dev->model->flags, ModelFlag::DARK_CALIBRATION)) {
+ genesys_dark_shading_by_constant(*dev);
}
/* send the shading coefficient when doing whole line shading
@@ -3099,7 +3912,7 @@ static void genesys_sheetfed_calibration(Genesys_Device* dev, Genesys_Sensor& se
dev->cmd_set->eject_document(dev);
// restore settings
- dev->settings.xres = sensor.optical_res;
+ dev->settings.xres = sensor.full_resolution;
}
/**
@@ -3129,22 +3942,23 @@ static void genesys_warmup_lamp(Genesys_Device* dev)
{
DBG_HELPER(dbg);
unsigned seconds = 0;
- int pixel;
- int channels, total_size;
- double first_average = 0;
- double second_average = 0;
- int difference = 255;
- int lines = 3;
const auto& sensor = sanei_genesys_find_sensor_any(dev);
- dev->cmd_set->init_regs_for_warmup(dev, sensor, &dev->reg, &channels, &total_size);
+ dev->cmd_set->init_regs_for_warmup(dev, sensor, &dev->reg);
+ dev->interface->write_registers(dev->reg);
+
+ auto total_pixels = dev->session.output_pixels;
+ auto total_size = dev->session.output_line_bytes;
+ auto channels = dev->session.params.channels;
+ auto lines = dev->session.output_line_count;
+
std::vector<uint8_t> first_line(total_size);
std::vector<uint8_t> second_line(total_size);
- do
- {
- DBG(DBG_info, "%s: one more loop\n", __func__);
+ do {
+ first_line = second_line;
+
dev->cmd_set->begin_scan(dev, sensor, &dev->reg, false);
if (is_testing_mode()) {
@@ -3155,72 +3969,44 @@ static void genesys_warmup_lamp(Genesys_Device* dev)
wait_until_buffer_non_empty(dev);
- try {
- sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size);
- } catch (...) {
- // FIXME: document why this retry is here
- sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size);
- }
-
+ sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
dev->cmd_set->end_scan(dev, &dev->reg, true);
- dev->interface->sleep_ms(1000);
- seconds++;
+ // compute difference between the two scans
+ double first_average = 0;
+ double second_average = 0;
+ for (unsigned pixel = 0; pixel < total_size; pixel++) {
+ // 16 bit data
+ if (dev->session.params.depth == 16) {
+ first_average += (first_line[pixel] + first_line[pixel + 1] * 256);
+ second_average += (second_line[pixel] + second_line[pixel + 1] * 256);
+ pixel++;
+ } else {
+ first_average += first_line[pixel];
+ second_average += second_line[pixel];
+ }
+ }
- dev->cmd_set->begin_scan(dev, sensor, &dev->reg, false);
+ first_average /= total_pixels;
+ second_average /= total_pixels;
- wait_until_buffer_non_empty(dev);
+ if (dbg_log_image_data()) {
+ write_tiff_file("gl_warmup1.tiff", first_line.data(), dev->session.params.depth,
+ channels, total_size / (lines * channels), lines);
+ write_tiff_file("gl_warmup2.tiff", second_line.data(), dev->session.params.depth,
+ channels, total_size / (lines * channels), lines);
+ }
- sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
- dev->cmd_set->end_scan(dev, &dev->reg, true);
+ DBG(DBG_info, "%s: average 1 = %.2f, average 2 = %.2f\n", __func__, first_average,
+ second_average);
- /* compute difference between the two scans */
- for (pixel = 0; pixel < total_size; pixel++)
- {
- // 16 bit data
- if (dev->session.params.depth == 16) {
- first_average += (first_line[pixel] + first_line[pixel + 1] * 256);
- second_average += (second_line[pixel] + second_line[pixel + 1] * 256);
- pixel++;
- }
- else
- {
- first_average += first_line[pixel];
- second_average += second_line[pixel];
- }
- }
- if (dev->session.params.depth == 16) {
- first_average /= pixel;
- second_average /= pixel;
- difference = static_cast<int>(std::fabs(first_average - second_average));
- DBG(DBG_info, "%s: average = %.2f, diff = %.3f\n", __func__,
- 100 * ((second_average) / (256 * 256)),
- 100 * (difference / second_average));
-
- if (second_average > (100 * 256)
- && (difference / second_average) < 0.002)
- break;
- }
- else
- {
- first_average /= pixel;
- second_average /= pixel;
- if (DBG_LEVEL >= DBG_data)
- {
- sanei_genesys_write_pnm_file("gl_warmup1.pnm", first_line.data(), 8, channels,
- total_size / (lines * channels), lines);
- sanei_genesys_write_pnm_file("gl_warmup2.pnm", second_line.data(), 8, channels,
- total_size / (lines * channels), lines);
- }
- DBG(DBG_info, "%s: average 1 = %.2f, average 2 = %.2f\n", __func__, first_average,
- second_average);
- /* if delta below 15/255 ~= 5.8%, lamp is considred warm enough */
- if (fabs (first_average - second_average) < 15
- && second_average > 55)
- break;
- }
+ float average_difference = std::fabs(first_average - second_average) / second_average;
+ if (second_average > 0 && average_difference < 0.005)
+ {
+ dbg.vlog(DBG_info, "difference: %f, exiting", average_difference);
+ break;
+ }
- /* sleep another second before next loop */
dev->interface->sleep_ms(1000);
seconds++;
} while (seconds < WARMUP_TIME);
@@ -3236,6 +4022,37 @@ static void genesys_warmup_lamp(Genesys_Device* dev)
}
}
+static void init_regs_for_scan(Genesys_Device& dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs)
+{
+ DBG_HELPER(dbg);
+ debug_dump(DBG_info, dev.settings);
+
+ auto session = dev.cmd_set->calculate_scan_session(&dev, sensor, dev.settings);
+
+ 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)
+ {
+ /* Fast move to scan area:
+
+ We don't move fast the whole distance since it would involve computing
+ acceleration/deceleration distance for scan resolution. So leave a remainder for it so
+ scan makes the final move tuning
+ */
+
+ if (dev.settings.get_channels() * dev.settings.yres >= 600 && session.params.starty > 700) {
+ scanner_move(dev, dev.model->default_method,
+ static_cast<unsigned>(session.params.starty - 500),
+ Direction::FORWARD);
+ session.params.starty = 500;
+ }
+ compute_session(&dev, session, sensor);
+ }
+
+ dev.cmd_set->init_regs_for_scan_session(&dev, sensor, &regs, session);
+}
// High-level start of scanning
static void genesys_start_scan(Genesys_Device* dev, bool lamp_off)
@@ -3243,6 +4060,7 @@ static void genesys_start_scan(Genesys_Device* dev, bool lamp_off)
DBG_HELPER(dbg);
unsigned int steps, expected;
+
/* since not all scanners are set ot wait for head to park
* we check we are not still parking before starting a new scan */
if (dev->parking) {
@@ -3254,38 +4072,30 @@ static void genesys_start_scan(Genesys_Device* dev, bool lamp_off)
/* wait for lamp warmup : until a warmup for TRANSPARENCY is designed, skip
* it when scanning from XPA. */
- if (!(dev->model->flags & GENESYS_FLAG_SKIP_WARMUP)
- && (dev->settings.scan_method == ScanMethod::FLATBED))
+ if (has_flag(dev->model->flags, ModelFlag::WARMUP) &&
+ (dev->settings.scan_method != ScanMethod::TRANSPARENCY_INFRARED))
{
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ scanner_move_to_ta(*dev);
+ }
+
genesys_warmup_lamp(dev);
}
/* set top left x and y values by scanning the internals if flatbed scanners */
if (!dev->model->is_sheetfed) {
- /* do the geometry detection only once */
- if ((dev->model->flags & GENESYS_FLAG_SEARCH_START)
- && (dev->model->y_offset_calib_white == 0))
- {
- dev->cmd_set->search_start_position (dev);
-
- dev->parking = false;
- dev->cmd_set->move_back_home(dev, true);
- }
- else
- {
- /* Go home */
- /* TODO: check we can drop this since we cannot have the
- scanner's head wandering here */
- dev->parking = false;
- dev->cmd_set->move_back_home(dev, true);
- }
+ // TODO: check we can drop this since we cannot have the scanner's head wandering here
+ dev->parking = false;
+ dev->cmd_set->move_back_home(dev, true);
}
/* move to calibration area for transparency adapter */
if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
- dev->cmd_set->move_to_ta(dev);
+ scanner_move_to_ta(*dev);
}
/* load document if needed (for sheetfed scanner for instance) */
@@ -3304,22 +4114,18 @@ static void genesys_start_scan(Genesys_Device* dev, bool lamp_off)
/* try to use cached calibration first */
if (!genesys_restore_calibration (dev, sensor))
{
- /* calibration : sheetfed scanners can't calibrate before each scan */
- /* and also those who have the NO_CALIBRATION flag */
- if (!(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION) && !dev->model->is_sheetfed) {
+ // calibration : sheetfed scanners can't calibrate before each scan.
+ // also don't run calibration for those scanners where all passes are disabled
+ bool shading_disabled =
+ has_flag(dev->model->flags, ModelFlag::DISABLE_ADC_CALIBRATION) &&
+ has_flag(dev->model->flags, ModelFlag::DISABLE_EXPOSURE_CALIBRATION) &&
+ has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION);
+ if (!shading_disabled && !dev->model->is_sheetfed) {
genesys_scanner_calibration(dev, sensor);
- genesys_save_calibration (dev, sensor);
- }
- else
- {
+ genesys_save_calibration(dev, sensor);
+ } else {
DBG(DBG_warn, "%s: no calibration done\n", __func__);
- }
- }
-
- /* build look up table for dynamic lineart */
- if (dev->settings.scan_mode == ScanColorMode::LINEART) {
- sanei_genesys_load_lut(dev->lineart_lut, 8, 8, 50, 205, dev->settings.threshold_curve,
- dev->settings.threshold-127);
+ }
}
dev->cmd_set->wait_for_motor_stop(dev);
@@ -3331,10 +4137,10 @@ static void genesys_start_scan(Genesys_Device* dev, bool lamp_off)
if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
- dev->cmd_set->move_to_ta(dev);
+ scanner_move_to_ta(*dev);
}
- dev->cmd_set->init_regs_for_scan(dev, sensor);
+ init_regs_for_scan(*dev, sensor, dev->reg);
/* no lamp during scan */
if (lamp_off) {
@@ -3344,7 +4150,7 @@ static void genesys_start_scan(Genesys_Device* dev, bool lamp_off)
/* GL124 is using SHDAREA, so we have to wait for scan to be set up before
* sending shading data */
if (dev->cmd_set->has_send_shading_data() &&
- !(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION))
+ !has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION))
{
genesys_send_shading_coefficient(dev, sensor);
}
@@ -3386,33 +4192,6 @@ static void genesys_start_scan(Genesys_Device* dev, bool lamp_off)
}
}
-static void genesys_fill_read_buffer(Genesys_Device* dev)
-{
- DBG_HELPER(dbg);
-
- /* for sheetfed scanner, we must check is document is shorter than
- * the requested scan */
- if (dev->model->is_sheetfed) {
- dev->cmd_set->detect_document_end(dev);
- }
-
- std::size_t size = dev->read_buffer.size() - dev->read_buffer.avail();
-
- /* due to sensors and motors, not all data can be directly used. It
- * may have to be read from another intermediate buffer and then processed.
- * There are currently 3 intermediate stages:
- * - handling of odd/even sensors
- * - handling of line interpolation for motors that can't have low
- * enough dpi
- * - handling of multi-segments sensors
- *
- * This is also the place where full duplex data will be handled.
- */
- dev->pipeline_buffer.get_data(size, dev->read_buffer.get_write_pos(size));
-
- dev->read_buffer.produce(size);
-}
-
/* this function does the effective data read in a manner that suits
the scanner. It does data reordering and resizing if need.
It also manages EOF and I/O errors, and line distance correction.
@@ -3422,8 +4201,6 @@ static void genesys_read_ordered_data(Genesys_Device* dev, SANE_Byte* destinatio
{
DBG_HELPER(dbg);
size_t bytes = 0;
- uint8_t *work_buffer_src;
- Genesys_Buffer *src_buffer;
if (!dev->read_active) {
*len = 0;
@@ -3439,7 +4216,7 @@ static void genesys_read_ordered_data(Genesys_Device* dev, SANE_Byte* destinatio
{
/* issue park command immediatly in case scanner can handle it
* so we save time */
- if (!dev->model->is_sheetfed && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) &&
+ if (!dev->model->is_sheetfed && !has_flag(dev->model->flags, ModelFlag::MUST_WAIT) &&
!dev->parking)
{
dev->cmd_set->move_back_home(dev, false);
@@ -3448,61 +4225,22 @@ static void genesys_read_ordered_data(Genesys_Device* dev, SANE_Byte* destinatio
throw SaneException(SANE_STATUS_EOF, "nothing more to scan: EOF");
}
-/* convert data */
-/*
- 0. fill_read_buffer
--------------- read_buffer ----------------------
- 1a). (opt)uncis (assumes color components to be laid out
- planar)
- 1b). (opt)reverse_RGB (assumes pixels to be BGR or BBGGRR))
--------------- lines_buffer ----------------------
- 2a). (opt)line_distance_correction (assumes RGB or RRGGBB)
- 2b). (opt)unstagger (assumes pixels to be depth*channels/8
- bytes long, unshrinked)
-------------- shrink_buffer ---------------------
- 3. (opt)shrink_lines (assumes component separation in pixels)
--------------- out_buffer -----------------------
- 4. memcpy to destination (for lineart with bit reversal)
-*/
-/*FIXME: for lineart we need sub byte addressing in buffers, or conversion to
- bytes at 0. and back to bits at 4.
-Problems with the first approach:
- - its not clear how to check if we need to output an incomplete byte
- because it is the last one.
- */
-/*FIXME: add lineart support for gl646. in the meantime add logic to convert
- from gray to lineart at the end? would suffer the above problem,
- total_bytes_to_read and total_bytes_read help in that case.
- */
-
if (is_testing_mode()) {
if (dev->total_bytes_read + *len > dev->total_bytes_to_read) {
*len = dev->total_bytes_to_read - dev->total_bytes_read;
}
dev->total_bytes_read += *len;
} else {
- genesys_fill_read_buffer(dev);
-
- src_buffer = &(dev->read_buffer);
-
- /* move data to destination */
- bytes = std::min(src_buffer->avail(), *len);
-
- work_buffer_src = src_buffer->get_read_pos();
-
- std::memcpy(destination, work_buffer_src, bytes);
- *len = bytes;
+ if (dev->model->is_sheetfed) {
+ dev->cmd_set->detect_document_end(dev);
+ }
- /* avoid signaling some extra data because we have treated a full block
- * on the last block */
if (dev->total_bytes_read + *len > dev->total_bytes_to_read) {
*len = dev->total_bytes_to_read - dev->total_bytes_read;
}
- /* count bytes sent to frontend */
+ dev->pipeline_buffer.get_data(*len, destination);
dev->total_bytes_read += *len;
-
- src_buffer->consume(bytes);
}
/* end scan if all needed data have been read */
@@ -3576,181 +4314,113 @@ static unsigned pick_resolution(const std::vector<unsigned>& resolutions, unsign
return best_res;
}
-static void calc_parameters(Genesys_Scanner* s)
+static Genesys_Settings calculate_scan_settings(Genesys_Scanner* s)
{
DBG_HELPER(dbg);
- double tl_x = 0, tl_y = 0, br_x = 0, br_y = 0;
- tl_x = SANE_UNFIX(s->pos_top_left_x);
- tl_y = SANE_UNFIX(s->pos_top_left_y);
- br_x = SANE_UNFIX(s->pos_bottom_right_x);
- br_y = SANE_UNFIX(s->pos_bottom_right_y);
+ const auto* dev = s->dev;
+ Genesys_Settings settings;
+ settings.scan_method = s->scan_method;
+ settings.scan_mode = option_string_to_scan_color_mode(s->mode);
- s->params.last_frame = true; /* only single pass scanning supported */
+ settings.depth = s->bit_depth;
- if (s->mode == SANE_VALUE_SCAN_MODE_GRAY || s->mode == SANE_VALUE_SCAN_MODE_LINEART) {
- s->params.format = SANE_FRAME_GRAY;
- } else {
- s->params.format = SANE_FRAME_RGB;
+ if (settings.depth > 8) {
+ settings.depth = 16;
+ } else if (settings.depth < 8) {
+ settings.depth = 1;
}
- if (s->mode == SANE_VALUE_SCAN_MODE_LINEART) {
- s->params.depth = 1;
- } else {
- s->params.depth = s->bit_depth;
- }
-
- s->dev->settings.scan_method = s->scan_method;
- const auto& resolutions = s->dev->model->get_resolution_settings(s->dev->settings.scan_method);
-
- s->dev->settings.depth = s->bit_depth;
+ const auto& resolutions = dev->model->get_resolution_settings(settings.scan_method);
- /* interpolation */
- s->dev->settings.disable_interpolation = s->disable_interpolation;
+ settings.xres = pick_resolution(resolutions.resolutions_x, s->resolution, "X");
+ settings.yres = pick_resolution(resolutions.resolutions_y, s->resolution, "Y");
- // FIXME: use correct sensor
- const auto& sensor = sanei_genesys_find_sensor_any(s->dev);
-
- // hardware settings
- if (static_cast<unsigned>(s->resolution) > sensor.optical_res &&
- s->dev->settings.disable_interpolation)
- {
- s->dev->settings.xres = sensor.optical_res;
- } else {
- s->dev->settings.xres = s->resolution;
- }
- s->dev->settings.yres = s->resolution;
+ settings.tl_x = fixed_to_float(s->pos_top_left_x);
+ settings.tl_y = fixed_to_float(s->pos_top_left_y);
+ float br_x = fixed_to_float(s->pos_bottom_right_x);
+ float br_y = fixed_to_float(s->pos_bottom_right_y);
- s->dev->settings.xres = pick_resolution(resolutions.resolutions_x, s->dev->settings.xres, "X");
- s->dev->settings.yres = pick_resolution(resolutions.resolutions_y, s->dev->settings.yres, "Y");
-
- s->params.lines = static_cast<unsigned>(((br_y - tl_y) * s->dev->settings.yres) /
+ settings.lines = static_cast<unsigned>(((br_y - settings.tl_y) * settings.yres) /
MM_PER_INCH);
- unsigned pixels_per_line = static_cast<unsigned>(((br_x - tl_x) * s->dev->settings.xres) /
- MM_PER_INCH);
-
- /* we need an even pixels number
- * TODO invert test logic or generalize behaviour across all ASICs */
- if ((s->dev->model->flags & GENESYS_FLAG_SIS_SENSOR) ||
- s->dev->model->asic_type == AsicType::GL847 ||
- s->dev->model->asic_type == AsicType::GL124 ||
- s->dev->model->asic_type == AsicType::GL845 ||
- s->dev->model->asic_type == AsicType::GL846 ||
- s->dev->model->asic_type == AsicType::GL843)
- {
- if (s->dev->settings.xres <= 1200) {
- pixels_per_line = (pixels_per_line / 4) * 4;
- } else if (s->dev->settings.xres < s->dev->settings.yres) {
- // BUG: this is an artifact of the fact that the resolution was twice as large than
- // the actual resolution when scanning above the supported scanner X resolution
- pixels_per_line = (pixels_per_line / 8) * 8;
- } else {
- pixels_per_line = (pixels_per_line / 16) * 16;
- }
- }
-
- /* corner case for true lineart for sensor with several segments
- * or when xres is doubled to match yres */
- if (s->dev->settings.xres >= 1200 && (
- s->dev->model->asic_type == AsicType::GL124 ||
- s->dev->model->asic_type == AsicType::GL847 ||
- s->dev->session.params.xres < s->dev->session.params.yres))
- {
- if (s->dev->settings.xres < s->dev->settings.yres) {
- // FIXME: this is an artifact of the fact that the resolution was twice as large than
- // the actual resolution when scanning above the supported scanner X resolution
- pixels_per_line = (pixels_per_line / 8) * 8;
- } else {
- pixels_per_line = (pixels_per_line / 16) * 16;
- }
- }
-
- unsigned xres_factor = s->resolution / s->dev->settings.xres;
- unsigned bytes_per_line = 0;
-
- if (s->params.depth > 8)
- {
- s->params.depth = 16;
- bytes_per_line = 2 * pixels_per_line;
- }
- else if (s->params.depth == 1)
- {
- // round down pixel number. This will is lossy operation, at most 7 pixels will be lost
- pixels_per_line = (pixels_per_line / 8) * 8;
- bytes_per_line = pixels_per_line / 8;
- } else {
- bytes_per_line = pixels_per_line;
- }
- if (s->params.format == SANE_FRAME_RGB) {
- bytes_per_line *= 3;
- }
+ unsigned pixels_per_line = static_cast<unsigned>(((br_x - settings.tl_x) * settings.xres) /
+ MM_PER_INCH);
- s->dev->settings.scan_mode = option_string_to_scan_color_mode(s->mode);
+ const auto& sensor = sanei_genesys_find_sensor(dev, settings.xres, settings.get_channels(),
+ settings.scan_method);
- s->dev->settings.lines = s->params.lines;
- s->dev->settings.pixels = pixels_per_line;
- s->dev->settings.requested_pixels = pixels_per_line * xres_factor;
- s->params.pixels_per_line = pixels_per_line * xres_factor;
- s->params.bytes_per_line = bytes_per_line * xres_factor;
- s->dev->settings.tl_x = tl_x;
- s->dev->settings.tl_y = tl_y;
+ pixels_per_line = session_adjust_output_pixels(pixels_per_line, *dev, sensor,
+ settings.xres, settings.yres, true);
- // threshold setting
- s->dev->settings.threshold = static_cast<int>(2.55 * (SANE_UNFIX(s->threshold)));
+ unsigned xres_factor = s->resolution / settings.xres;
+ settings.pixels = pixels_per_line;
+ settings.requested_pixels = pixels_per_line * xres_factor;
- // color filter
if (s->color_filter == "Red") {
- s->dev->settings.color_filter = ColorFilter::RED;
+ settings.color_filter = ColorFilter::RED;
} else if (s->color_filter == "Green") {
- s->dev->settings.color_filter = ColorFilter::GREEN;
+ settings.color_filter = ColorFilter::GREEN;
} else if (s->color_filter == "Blue") {
- s->dev->settings.color_filter = ColorFilter::BLUE;
+ settings.color_filter = ColorFilter::BLUE;
} else {
- s->dev->settings.color_filter = ColorFilter::NONE;
+ settings.color_filter = ColorFilter::NONE;
}
- // true gray
if (s->color_filter == "None") {
- s->dev->settings.true_gray = 1;
+ settings.true_gray = 1;
} else {
- s->dev->settings.true_gray = 0;
+ settings.true_gray = 0;
}
- // threshold curve for dynamic rasterization
- s->dev->settings.threshold_curve = s->threshold_curve;
-
- /* some digital processing requires the whole picture to be buffered */
- /* no digital processing takes place when doing preview, or when bit depth is
- * higher than 8 bits */
- if ((s->swdespeck || s->swcrop || s->swdeskew || s->swderotate ||(SANE_UNFIX(s->swskip)>0))
- && (!s->preview)
- && (s->bit_depth <= 8))
- {
- s->dev->buffer_image = true;
- }
- else
- {
- s->dev->buffer_image = false;
+ // brigthness and contrast only for for 8 bit scans
+ if (s->bit_depth == 8) {
+ settings.contrast = (s->contrast * 127) / 100;
+ settings.brightness = (s->brightness * 127) / 100;
+ } else {
+ settings.contrast = 0;
+ settings.brightness = 0;
}
- /* brigthness and contrast only for for 8 bit scans */
- if(s->bit_depth <= 8)
- {
- s->dev->settings.contrast = (s->contrast * 127) / 100;
- s->dev->settings.brightness = (s->brightness * 127) / 100;
- }
- else
- {
- s->dev->settings.contrast=0;
- s->dev->settings.brightness=0;
+ settings.expiration_time = s->expiration_time;
+
+ return settings;
+}
+
+static SANE_Parameters calculate_scan_parameters(const Genesys_Device& dev,
+ const Genesys_Settings& settings)
+{
+ DBG_HELPER(dbg);
+
+ auto sensor = sanei_genesys_find_sensor(&dev, settings.xres, settings.get_channels(),
+ settings.scan_method);
+ auto session = dev.cmd_set->calculate_scan_session(&dev, sensor, settings);
+ auto pipeline = build_image_pipeline(dev, session, 0, false);
+
+ SANE_Parameters params;
+ if (settings.scan_mode == ScanColorMode::GRAY) {
+ params.format = SANE_FRAME_GRAY;
+ } else {
+ params.format = SANE_FRAME_RGB;
}
+ // only single-pass scanning supported
+ params.last_frame = true;
+ params.depth = settings.depth;
+ params.lines = pipeline.get_output_height();
+ params.pixels_per_line = pipeline.get_output_width();
+ params.bytes_per_line = pipeline.get_output_row_bytes();
- /* cache expiration time */
- s->dev->settings.expiration_time = s->expiration_time;
+ return params;
}
+static void calc_parameters(Genesys_Scanner* s)
+{
+ DBG_HELPER(dbg);
+
+ s->dev->settings = calculate_scan_settings(s);
+ s->params = calculate_scan_parameters(*s->dev, s->dev->settings);
+}
static void create_bpp_list (Genesys_Scanner * s, const std::vector<unsigned>& bpp)
{
@@ -3760,7 +4430,7 @@ static void create_bpp_list (Genesys_Scanner * s, const std::vector<unsigned>& b
/** @brief this function initialize a gamma vector based on the ASIC:
* Set up a default gamma table vector based on device description
- * gl646: 12 or 14 bits gamma table depending on GENESYS_FLAG_14BIT_GAMMA
+ * gl646: 12 or 14 bits gamma table depending on ModelFlag::GAMMA_14BIT
* gl84x: 16 bits
* gl12x: 16 bits
* @param scanner pointer to scanner session to get options
@@ -3776,8 +4446,7 @@ init_gamma_vector_option (Genesys_Scanner * scanner, int option)
scanner->opt[option].unit = SANE_UNIT_NONE;
scanner->opt[option].constraint_type = SANE_CONSTRAINT_RANGE;
if (scanner->dev->model->asic_type == AsicType::GL646) {
- if ((scanner->dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) != 0)
- {
+ if (has_flag(scanner->dev->model->flags, ModelFlag::GAMMA_14BIT)) {
scanner->opt[option].size = 16384 * sizeof (SANE_Word);
scanner->opt[option].constraint.range = &u14_range;
}
@@ -3802,9 +4471,9 @@ init_gamma_vector_option (Genesys_Scanner * scanner, int option)
static SANE_Range create_range(float size)
{
SANE_Range range;
- range.min = SANE_FIX(0.0);
- range.max = SANE_FIX(size);
- range.quant = SANE_FIX(0.0);
+ range.min = float_to_fixed(0.0);
+ range.max = float_to_fixed(size);
+ range.quant = float_to_fixed(0.0);
return range;
}
@@ -3855,7 +4524,7 @@ static std::string calibration_filename(Genesys_Device *currdev)
/* count models of the same names if several scanners attached */
if(s_devices->size() > 1) {
for (const auto& dev : *s_devices) {
- if (dev.model->model_id == currdev->model->model_id) {
+ if (dev.vendorId == currdev->vendorId && dev.productId == currdev->productId) {
count++;
}
}
@@ -3921,13 +4590,13 @@ static void set_xy_range_option_values(Genesys_Scanner& s)
{
if (s.scan_method == ScanMethod::FLATBED)
{
- s.opt_x_range = create_range(static_cast<float>(s.dev->model->x_size));
- s.opt_y_range = create_range(static_cast<float>(s.dev->model->y_size));
+ s.opt_x_range = create_range(s.dev->model->x_size);
+ s.opt_y_range = create_range(s.dev->model->y_size);
}
else
{
- s.opt_x_range = create_range(static_cast<float>(s.dev->model->x_size_ta));
- s.opt_y_range = create_range(static_cast<float>(s.dev->model->y_size_ta));
+ s.opt_x_range = create_range(s.dev->model->x_size_ta);
+ s.opt_y_range = create_range(s.dev->model->y_size_ta);
}
s.opt[OPT_TL_X].constraint.range = &s.opt_x_range;
@@ -3945,7 +4614,7 @@ static void init_options(Genesys_Scanner* s)
{
DBG_HELPER(dbg);
SANE_Int option;
- Genesys_Model *model = s->dev->model;
+ const Genesys_Model* model = s->dev->model;
memset (s->opt, 0, sizeof (s->opt));
@@ -4038,8 +4707,8 @@ static void init_options(Genesys_Scanner* s)
s->opt[OPT_GEOMETRY_GROUP].size = 0;
s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
- s->opt_x_range = create_range(static_cast<float>(model->x_size));
- s->opt_y_range = create_range(static_cast<float>(model->y_size));
+ s->opt_x_range = create_range(model->x_size);
+ s->opt_y_range = create_range(model->y_size);
// scan area
s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
@@ -4116,8 +4785,7 @@ static void init_options(Genesys_Scanner* s)
/* currently, there are only gamma table options in this group,
* so if the scanner doesn't support gamma table, disable the
* whole group */
- if (!(model->flags & GENESYS_FLAG_CUSTOM_GAMMA))
- {
+ if (!has_flag(model->flags, ModelFlag::CUSTOM_GAMMA)) {
s->opt[OPT_ENHANCEMENT_GROUP].cap |= SANE_CAP_INACTIVE;
s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
DBG(DBG_info, "%s: custom gamma disabled\n", __func__);
@@ -4127,61 +4795,6 @@ static void init_options(Genesys_Scanner* s)
* memory than used by the full scanned image and may fail at high
* resolution
*/
- /* software deskew */
- s->opt[OPT_SWDESKEW].name = "swdeskew";
- s->opt[OPT_SWDESKEW].title = "Software deskew";
- s->opt[OPT_SWDESKEW].desc = "Request backend to rotate skewed pages digitally";
- s->opt[OPT_SWDESKEW].type = SANE_TYPE_BOOL;
- s->opt[OPT_SWDESKEW].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
- s->swdeskew = false;
-
- /* software deskew */
- s->opt[OPT_SWDESPECK].name = "swdespeck";
- s->opt[OPT_SWDESPECK].title = "Software despeck";
- s->opt[OPT_SWDESPECK].desc = "Request backend to remove lone dots digitally";
- s->opt[OPT_SWDESPECK].type = SANE_TYPE_BOOL;
- s->opt[OPT_SWDESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
- s->swdespeck = false;
-
- /* software despeckle radius */
- s->opt[OPT_DESPECK].name = "despeck";
- s->opt[OPT_DESPECK].title = "Software despeckle diameter";
- s->opt[OPT_DESPECK].desc = "Maximum diameter of lone dots to remove from scan";
- s->opt[OPT_DESPECK].type = SANE_TYPE_INT;
- s->opt[OPT_DESPECK].unit = SANE_UNIT_NONE;
- s->opt[OPT_DESPECK].constraint_type = SANE_CONSTRAINT_RANGE;
- s->opt[OPT_DESPECK].constraint.range = &swdespeck_range;
- s->opt[OPT_DESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED | SANE_CAP_INACTIVE;
- s->despeck = 1;
-
- /* crop by software */
- s->opt[OPT_SWCROP].name = "swcrop";
- s->opt[OPT_SWCROP].title = SANE_I18N ("Software crop");
- s->opt[OPT_SWCROP].desc = SANE_I18N ("Request backend to remove border from pages digitally");
- s->opt[OPT_SWCROP].type = SANE_TYPE_BOOL;
- s->opt[OPT_SWCROP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
- s->opt[OPT_SWCROP].unit = SANE_UNIT_NONE;
- s->swcrop = false;
-
- /* Software blank page skip */
- s->opt[OPT_SWSKIP].name = "swskip";
- s->opt[OPT_SWSKIP].title = SANE_I18N ("Software blank skip percentage");
- s->opt[OPT_SWSKIP].desc = SANE_I18N("Request driver to discard pages with low numbers of dark pixels");
- s->opt[OPT_SWSKIP].type = SANE_TYPE_FIXED;
- s->opt[OPT_SWSKIP].unit = SANE_UNIT_PERCENT;
- s->opt[OPT_SWSKIP].constraint_type = SANE_CONSTRAINT_RANGE;
- s->opt[OPT_SWSKIP].constraint.range = &(percentage_range);
- s->opt[OPT_SWSKIP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
- s->swskip = 0; // disable by default
-
- /* Software Derotate */
- s->opt[OPT_SWDEROTATE].name = "swderotate";
- s->opt[OPT_SWDEROTATE].title = SANE_I18N ("Software derotate");
- s->opt[OPT_SWDEROTATE].desc = SANE_I18N("Request driver to detect and correct 90 degree image rotation");
- s->opt[OPT_SWDEROTATE].type = SANE_TYPE_BOOL;
- s->opt[OPT_SWDEROTATE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
- s->opt[OPT_SWDEROTATE].unit = SANE_UNIT_NONE;
- s->swderotate = false;
/* Software brightness */
s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
@@ -4214,39 +4827,6 @@ static void init_options(Genesys_Scanner* s)
s->opt[OPT_EXTRAS_GROUP].size = 0;
s->opt[OPT_EXTRAS_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
- /* BW threshold */
- s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
- s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
- s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
- s->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED;
- s->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT;
- s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
- s->opt[OPT_THRESHOLD].constraint.range = &percentage_range;
- s->threshold = SANE_FIX(50);
-
- /* BW threshold curve */
- s->opt[OPT_THRESHOLD_CURVE].name = "threshold-curve";
- s->opt[OPT_THRESHOLD_CURVE].title = SANE_I18N ("Threshold curve");
- s->opt[OPT_THRESHOLD_CURVE].desc = SANE_I18N ("Dynamic threshold curve, from light to dark, normally 50-65");
- s->opt[OPT_THRESHOLD_CURVE].type = SANE_TYPE_INT;
- s->opt[OPT_THRESHOLD_CURVE].unit = SANE_UNIT_NONE;
- s->opt[OPT_THRESHOLD_CURVE].constraint_type = SANE_CONSTRAINT_RANGE;
- s->opt[OPT_THRESHOLD_CURVE].constraint.range = &threshold_curve_range;
- s->threshold_curve = 50;
-
- /* disable_interpolation */
- s->opt[OPT_DISABLE_INTERPOLATION].name = "disable-interpolation";
- s->opt[OPT_DISABLE_INTERPOLATION].title =
- SANE_I18N ("Disable interpolation");
- s->opt[OPT_DISABLE_INTERPOLATION].desc =
- SANE_I18N
- ("When using high resolutions where the horizontal resolution is smaller "
- "than the vertical resolution this disables horizontal interpolation.");
- s->opt[OPT_DISABLE_INTERPOLATION].type = SANE_TYPE_BOOL;
- s->opt[OPT_DISABLE_INTERPOLATION].unit = SANE_UNIT_NONE;
- s->opt[OPT_DISABLE_INTERPOLATION].constraint_type = SANE_CONSTRAINT_NONE;
- s->disable_interpolation = false;
-
/* color filter */
s->opt[OPT_COLOR_FILTER].name = "color-filter";
s->opt[OPT_COLOR_FILTER].title = SANE_I18N ("Color filter");
@@ -4508,36 +5088,39 @@ check_present (SANE_String_Const devname) noexcept
return SANE_STATUS_GOOD;
}
-static Genesys_Device* attach_usb_device(const char* devname,
- std::uint16_t vendor_id, std::uint16_t product_id)
+const UsbDeviceEntry& get_matching_usb_dev(std::uint16_t vendor_id, std::uint16_t product_id,
+ std::uint16_t bcd_device)
{
- Genesys_USB_Device_Entry* found_usb_dev = nullptr;
for (auto& usb_dev : *s_usb_devices) {
- if (usb_dev.vendor == vendor_id &&
- usb_dev.product == product_id)
- {
- found_usb_dev = &usb_dev;
- break;
+ if (usb_dev.matches(vendor_id, product_id, bcd_device)) {
+ return usb_dev;
}
}
- if (found_usb_dev == nullptr) {
- throw SaneException("vendor 0x%xd product 0x%xd is not supported by this backend",
- vendor_id, product_id);
- }
+ throw SaneException("vendor 0x%x product 0x%x (bcdDevice 0x%x) "
+ "is not supported by this backend",
+ vendor_id, product_id, bcd_device);
+}
+
+static Genesys_Device* attach_usb_device(const char* devname,
+ std::uint16_t vendor_id, std::uint16_t product_id,
+ std::uint16_t bcd_device)
+{
+ const auto& usb_dev = get_matching_usb_dev(vendor_id, product_id, bcd_device);
s_devices->emplace_back();
Genesys_Device* dev = &s_devices->back();
dev->file_name = devname;
-
- dev->model = &found_usb_dev->model;
- dev->vendorId = found_usb_dev->vendor;
- dev->productId = found_usb_dev->product;
+ dev->vendorId = vendor_id;
+ dev->productId = product_id;
+ dev->model = &usb_dev.model();
dev->usb_mode = 0; // i.e. unset
dev->already_initialized = false;
return dev;
}
+static bool s_attach_device_by_name_evaluate_bcd_device = false;
+
static Genesys_Device* attach_device_by_name(SANE_String_Const devname, bool may_wait)
{
DBG_HELPER_ARGS(dbg, " devname: %s, may_wait = %d", devname, may_wait);
@@ -4560,26 +5143,31 @@ static Genesys_Device* attach_device_by_name(SANE_String_Const devname, bool may
usb_dev.open(devname);
DBG(DBG_info, "%s: device `%s' successfully opened\n", __func__, devname);
- int vendor, product;
- usb_dev.get_vendor_product(vendor, product);
+ auto vendor_id = usb_dev.get_vendor_id();
+ auto product_id = usb_dev.get_product_id();
+ auto bcd_device = UsbDeviceEntry::BCD_DEVICE_NOT_SET;
+ if (s_attach_device_by_name_evaluate_bcd_device) {
+ // when the device is already known before scanning, we don't want to call get_bcd_device()
+ // when iterating devices, as that will interfere with record/replay during testing.
+ bcd_device = usb_dev.get_bcd_device();
+ }
usb_dev.close();
/* KV-SS080 is an auxiliary device which requires a master device to be here */
- if(vendor == 0x04da && product == 0x100f)
- {
+ if (vendor_id == 0x04da && product_id == 0x100f) {
present = false;
- sanei_usb_find_devices (vendor, 0x1006, check_present);
- sanei_usb_find_devices (vendor, 0x1007, check_present);
- sanei_usb_find_devices (vendor, 0x1010, check_present);
+ sanei_usb_find_devices(vendor_id, 0x1006, check_present);
+ sanei_usb_find_devices(vendor_id, 0x1007, check_present);
+ sanei_usb_find_devices(vendor_id, 0x1010, check_present);
if (present == false) {
throw SaneException("master device not present");
}
}
- Genesys_Device* dev = attach_usb_device(devname, vendor, product);
+ Genesys_Device* dev = attach_usb_device(devname, vendor_id, product_id, bcd_device);
- DBG(DBG_info, "%s: found %s flatbed scanner %s at %s\n", __func__, dev->model->vendor,
- dev->model->model, dev->file_name.c_str());
+ DBG(DBG_info, "%s: found %u flatbed scanner %u at %s\n", __func__, vendor_id, product_id,
+ dev->file_name.c_str());
return dev;
}
@@ -4614,7 +5202,8 @@ static void probe_genesys_devices()
DBG_HELPER(dbg);
if (is_testing_mode()) {
attach_usb_device(get_testing_device_name().c_str(),
- get_testing_vendor_id(), get_testing_product_id());
+ get_testing_vendor_id(), get_testing_product_id(),
+ get_testing_bcd_device());
return;
}
@@ -4625,7 +5214,12 @@ static void probe_genesys_devices()
config.values = nullptr;
config.count = 0;
- TIE(sanei_configure_attach(GENESYS_CONFIG_FILE, &config, config_attach_genesys));
+ auto status = sanei_configure_attach(GENESYS_CONFIG_FILE, &config, config_attach_genesys);
+ if (status == SANE_STATUS_ACCESS_DENIED) {
+ dbg.vlog(DBG_error0, "Critical error: Couldn't access configuration file '%s'",
+ GENESYS_CONFIG_FILE);
+ }
+ TIE(status);
DBG(DBG_info, "%s: %zu devices currently attached\n", __func__, s_devices->size());
}
@@ -4637,7 +5231,7 @@ static void probe_genesys_devices()
of Genesys_Calibration_Cache as is.
*/
static const char* CALIBRATION_IDENT = "sane_genesys";
-static const int CALIBRATION_VERSION = 21;
+static const int CALIBRATION_VERSION = 31;
bool read_calibration(std::istream& str, Genesys_Device::Calibration& calibration,
const std::string& path)
@@ -4706,114 +5300,6 @@ static void write_calibration(Genesys_Device::Calibration& calibration, const st
write_calibration(str, calibration);
}
-/** @brief buffer scanned picture
- * In order to allow digital processing, we must be able to put all the
- * scanned picture in a buffer.
- */
-static void genesys_buffer_image(Genesys_Scanner *s)
-{
- DBG_HELPER(dbg);
- size_t maximum; /**> maximum bytes size of the scan */
- size_t len; /**> length of scanned data read */
- size_t total; /**> total of butes read */
- size_t size; /**> size of image buffer */
- size_t read_size; /**> size of reads */
- int lines; /** number of lines of the scan */
- Genesys_Device *dev = s->dev;
-
- /* compute maximum number of lines for the scan */
- if (s->params.lines > 0)
- {
- lines = s->params.lines;
- }
- else
- {
- lines = static_cast<int>((dev->model->y_size * dev->settings.yres) / MM_PER_INCH);
- }
- DBG(DBG_info, "%s: buffering %d lines of %d bytes\n", __func__, lines,
- s->params.bytes_per_line);
-
- /* maximum bytes to read */
- maximum = s->params.bytes_per_line * lines;
- if (s->dev->settings.scan_mode == ScanColorMode::LINEART) {
- maximum *= 8;
- }
-
- /* initial size of the read buffer */
- size =
- ((2048 * 2048) / s->params.bytes_per_line) * s->params.bytes_per_line;
-
- /* read size */
- read_size = size / 2;
-
- dev->img_buffer.resize(size);
-
- /* loop reading data until we reach maximum or EOF */
- total = 0;
- while (total < maximum) {
- len = size - maximum;
- if (len > read_size)
- {
- len = read_size;
- }
-
- try {
- genesys_read_ordered_data(dev, dev->img_buffer.data() + total, &len);
- } catch (const SaneException& e) {
- if (e.status() == SANE_STATUS_EOF) {
- // ideally we shouldn't end up here, but because computations are duplicated and
- // slightly different everywhere in the genesys backend, we have no other choice
- break;
- }
- throw;
- }
- total += len;
-
- // do we need to enlarge read buffer ?
- if (total + read_size > size) {
- size += read_size;
- dev->img_buffer.resize(size);
- }
- }
-
- /* since digital processing is going to take place,
- * issue head parking command so that the head move while
- * computing so we can save time
- */
- if (!dev->model->is_sheetfed && !dev->parking) {
- dev->cmd_set->move_back_home(dev, dev->model->flags & GENESYS_FLAG_MUST_WAIT);
- dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT);
- }
-
- /* in case of dynamic lineart, we have buffered gray data which
- * must be converted to lineart first */
- if (s->dev->settings.scan_mode == ScanColorMode::LINEART) {
- total/=8;
- std::vector<uint8_t> lineart(total);
-
- genesys_gray_lineart (dev,
- dev->img_buffer.data(),
- lineart.data(),
- dev->settings.pixels,
- (total*8)/dev->settings.pixels,
- dev->settings.threshold);
- dev->img_buffer = lineart;
- }
-
- /* update counters */
- dev->total_bytes_to_read = total;
- dev->total_bytes_read = 0;
-
- /* update params */
- s->params.lines = total / s->params.bytes_per_line;
- if (DBG_LEVEL >= DBG_io2)
- {
- sanei_genesys_write_pnm_file("gl_unprocessed.pnm", dev->img_buffer.data(), s->params.depth,
- s->params.format==SANE_FRAME_RGB ? 3 : 1,
- s->params.pixels_per_line, s->params.lines);
- }
-}
-
/* -------------------------- SANE API functions ------------------------- */
void sane_init_impl(SANE_Int * version_code, SANE_Auth_Callback authorize)
@@ -4839,9 +5325,6 @@ void sane_init_impl(SANE_Int * version_code, SANE_Auth_Callback authorize)
sanei_usb_init();
}
- /* init sanei_magic */
- sanei_magic_init();
-
s_scanners.init();
s_devices.init();
s_sane_devices.init();
@@ -4850,8 +5333,8 @@ void sane_init_impl(SANE_Int * version_code, SANE_Auth_Callback authorize)
genesys_init_sensor_tables();
genesys_init_frontend_tables();
genesys_init_gpo_tables();
+ genesys_init_memory_layout_tables();
genesys_init_motor_tables();
- genesys_init_motor_profile_tables();
genesys_init_usb_device_tables();
@@ -4864,6 +5347,7 @@ void sane_init_impl(SANE_Int * version_code, SANE_Auth_Callback authorize)
);
// cold-plug case :detection of allready connected scanners
+ s_attach_device_by_name_evaluate_bcd_device = false;
probe_genesys_devices();
}
@@ -4903,6 +5387,7 @@ void sane_get_devices_impl(const SANE_Device *** device_list, SANE_Bool local_on
// hot-plug case : detection of newly connected scanners */
sanei_usb_scan_devices();
}
+ s_attach_device_by_name_evaluate_bcd_device = true;
probe_genesys_devices();
s_sane_devices->clear();
@@ -4969,7 +5454,7 @@ static void sane_open_impl(SANE_String_Const devicename, SANE_Handle * handle)
}
if (dev) {
- DBG(DBG_info, "%s: found `%s' in devlist\n", __func__, dev->model->name);
+ DBG(DBG_info, "%s: found `%s' in devlist\n", __func__, dev->file_name.c_str());
} else if (is_testing_mode()) {
DBG(DBG_info, "%s: couldn't find `%s' in devlist, not attaching", __func__, devicename);
} else {
@@ -4991,37 +5476,53 @@ static void sane_open_impl(SANE_String_Const devicename, SANE_Handle * handle)
throw SaneException("could not find the device to open: %s", devicename);
}
- if (dev->model->flags & GENESYS_FLAG_UNTESTED)
- {
- DBG(DBG_error0, "WARNING: Your scanner is not fully supported or at least \n");
- DBG(DBG_error0, " had only limited testing. Please be careful and \n");
- DBG(DBG_error0, " report any failure/success to \n");
- DBG(DBG_error0, " sane-devel@alioth-lists.debian.net. Please provide as many\n");
- DBG(DBG_error0, " details as possible, e.g. the exact name of your\n");
- DBG(DBG_error0, " scanner and what does (not) work.\n");
- }
+ if (is_testing_mode()) {
+ // during testing we need to initialize dev->model before test scanner interface is created
+ // as that it needs to know what type of chip it needs to mimic.
+ auto vendor_id = get_testing_vendor_id();
+ auto product_id = get_testing_product_id();
+ auto bcd_device = get_testing_bcd_device();
- dbg.vstatus("open device '%s'", dev->file_name.c_str());
+ dev->model = &get_matching_usb_dev(vendor_id, product_id, bcd_device).model();
- if (is_testing_mode()) {
- auto interface = std::unique_ptr<TestScannerInterface>{new TestScannerInterface{dev}};
+ auto interface = std::unique_ptr<TestScannerInterface>{
+ new TestScannerInterface{dev, vendor_id, product_id, bcd_device}};
interface->set_checkpoint_callback(get_testing_checkpoint_callback());
dev->interface = std::move(interface);
+
+ dev->interface->get_usb_device().open(dev->file_name.c_str());
} else {
dev->interface = std::unique_ptr<ScannerInterfaceUsb>{new ScannerInterfaceUsb{dev}};
+
+ dbg.vstatus("open device '%s'", dev->file_name.c_str());
+ dev->interface->get_usb_device().open(dev->file_name.c_str());
+ dbg.clear();
+
+ auto bcd_device = dev->interface->get_usb_device().get_bcd_device();
+
+ dev->model = &get_matching_usb_dev(dev->vendorId, dev->productId, bcd_device).model();
+ }
+
+ dbg.vlog(DBG_info, "Opened device %s", dev->model->name);
+
+ if (has_flag(dev->model->flags, ModelFlag::UNTESTED)) {
+ DBG(DBG_error0, "WARNING: Your scanner is not fully supported or at least \n");
+ DBG(DBG_error0, " had only limited testing. Please be careful and \n");
+ DBG(DBG_error0, " report any failure/success to \n");
+ DBG(DBG_error0, " sane-devel@alioth-lists.debian.net. Please provide as many\n");
+ DBG(DBG_error0, " details as possible, e.g. the exact name of your\n");
+ DBG(DBG_error0, " scanner and what does (not) work.\n");
}
- dev->interface->get_usb_device().open(dev->file_name.c_str());
- dbg.clear();
s_scanners->push_back(Genesys_Scanner());
auto* s = &s_scanners->back();
- s->dev = dev;
+ s->dev = dev;
s->scanning = false;
- s->dev->parking = false;
- s->dev->read_active = false;
- s->dev->force_calibration = 0;
- s->dev->line_count = 0;
+ dev->parking = false;
+ dev->read_active = false;
+ dev->force_calibration = 0;
+ dev->line_count = 0;
*handle = s;
@@ -5029,31 +5530,18 @@ static void sane_open_impl(SANE_String_Const devicename, SANE_Handle * handle)
sanei_genesys_init_structs (dev);
}
+ dev->cmd_set = create_cmd_set(dev->model->asic_type);
+
init_options(s);
- sanei_genesys_init_cmd_set(s->dev);
+ DBG_INIT();
// FIXME: we create sensor tables for the sensor, this should happen when we know which sensor
// we will select
dev->cmd_set->init(dev);
// some hardware capabilities are detected through sensors
- s->dev->cmd_set->update_hardware_sensors (s);
-
- /* here is the place to fetch a stored calibration cache */
- if (s->dev->force_calibration == 0)
- {
- auto path = calibration_filename(s->dev);
- s->calibration_file = path;
- s->dev->calib_file = path;
- DBG(DBG_info, "%s: Calibration filename set to:\n", __func__);
- DBG(DBG_info, "%s: >%s<\n", __func__, s->dev->calib_file.c_str());
-
- catch_all_exceptions(__func__, [&]()
- {
- sanei_genesys_read_calibration(s->dev->calibration_cache, s->dev->calib_file);
- });
- }
+ dev->cmd_set->update_hardware_sensors (s);
}
SANE_GENESYS_API_LINKAGE
@@ -5085,46 +5573,42 @@ sane_close_impl(SANE_Handle handle)
return; /* oops, not a handle we know about */
}
- Genesys_Scanner* s = &*it;
+ auto* dev = it->dev;
- /* eject document for sheetfed scanners */
- if (s->dev->model->is_sheetfed) {
- catch_all_exceptions(__func__, [&](){ s->dev->cmd_set->eject_document(s->dev); });
- }
- else
- {
- /* in case scanner is parking, wait for the head
- * to reach home position */
- if (s->dev->parking) {
- sanei_genesys_wait_for_home(s->dev);
+ // eject document for sheetfed scanners
+ if (dev->model->is_sheetfed) {
+ catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); });
+ } else {
+ // in case scanner is parking, wait for the head to reach home position
+ if (dev->parking) {
+ sanei_genesys_wait_for_home(dev);
}
}
// enable power saving before leaving
- s->dev->cmd_set->save_power(s->dev, true);
+ dev->cmd_set->save_power(dev, true);
// here is the place to store calibration cache
- if (s->dev->force_calibration == 0 && !is_testing_mode()) {
- catch_all_exceptions(__func__, [&](){ write_calibration(s->dev->calibration_cache,
- s->dev->calib_file); });
+ if (dev->force_calibration == 0 && !is_testing_mode()) {
+ catch_all_exceptions(__func__, [&](){ write_calibration(dev->calibration_cache,
+ dev->calib_file); });
}
- s->dev->already_initialized = false;
-
- s->dev->clear();
+ dev->already_initialized = false;
+ dev->clear();
// LAMP OFF : same register across all the ASICs */
- s->dev->interface->write_register(0x03, 0x00);
+ dev->interface->write_register(0x03, 0x00);
- catch_all_exceptions(__func__, [&](){ s->dev->interface->get_usb_device().clear_halt(); });
+ catch_all_exceptions(__func__, [&](){ dev->interface->get_usb_device().clear_halt(); });
// we need this to avoid these ASIC getting stuck in bulk writes
- catch_all_exceptions(__func__, [&](){ s->dev->interface->get_usb_device().reset(); });
+ catch_all_exceptions(__func__, [&](){ dev->interface->get_usb_device().reset(); });
- // not freeing s->dev because it's in the dev list
- catch_all_exceptions(__func__, [&](){ s->dev->interface->get_usb_device().close(); });
+ // not freeing dev because it's in the dev list
+ catch_all_exceptions(__func__, [&](){ dev->interface->get_usb_device().close(); });
- s_scanners->erase(it);
+ s_scanners->erase(it);
}
SANE_GENESYS_API_LINKAGE
@@ -5174,7 +5658,7 @@ static void print_option(DebugMessageHelper& dbg, const Genesys_Scanner& s, int
return;
}
case SANE_TYPE_FIXED: {
- dbg.vlog(DBG_proc, "value: %f", SANE_UNFIX(*reinterpret_cast<SANE_Word*>(val)));
+ dbg.vlog(DBG_proc, "value: %f", fixed_to_float(*reinterpret_cast<SANE_Word*>(val)));
return;
}
case SANE_TYPE_STRING: {
@@ -5189,18 +5673,19 @@ static void print_option(DebugMessageHelper& dbg, const Genesys_Scanner& s, int
static void get_option_value(Genesys_Scanner* s, int option, void* val)
{
DBG_HELPER_ARGS(dbg, "option: %s (%d)", s->opt[option].name, option);
+ auto* dev = s->dev;
unsigned int i;
SANE_Word* table = nullptr;
std::vector<uint16_t> gamma_table;
unsigned option_size = 0;
const Genesys_Sensor* sensor = nullptr;
- if (sanei_genesys_has_sensor(s->dev, s->dev->settings.xres, s->dev->settings.get_channels(),
- s->dev->settings.scan_method))
+ if (sanei_genesys_has_sensor(dev, dev->settings.xres, dev->settings.get_channels(),
+ dev->settings.scan_method))
{
- sensor = &sanei_genesys_find_sensor(s->dev, s->dev->settings.xres,
- s->dev->settings.get_channels(),
- s->dev->settings.scan_method);
+ sensor = &sanei_genesys_find_sensor(dev, dev->settings.xres,
+ dev->settings.get_channels(),
+ dev->settings.scan_method);
}
switch (option)
@@ -5231,39 +5716,12 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
case OPT_PREVIEW:
*reinterpret_cast<SANE_Word*>(val) = s->preview;
break;
- case OPT_THRESHOLD:
- *reinterpret_cast<SANE_Word*>(val) = s->threshold;
- break;
- case OPT_THRESHOLD_CURVE:
- *reinterpret_cast<SANE_Word*>(val) = s->threshold_curve;
- break;
- case OPT_DISABLE_INTERPOLATION:
- *reinterpret_cast<SANE_Word*>(val) = s->disable_interpolation;
- break;
case OPT_LAMP_OFF:
*reinterpret_cast<SANE_Word*>(val) = s->lamp_off;
break;
case OPT_LAMP_OFF_TIME:
*reinterpret_cast<SANE_Word*>(val) = s->lamp_off_time;
break;
- case OPT_SWDESKEW:
- *reinterpret_cast<SANE_Word*>(val) = s->swdeskew;
- break;
- case OPT_SWCROP:
- *reinterpret_cast<SANE_Word*>(val) = s->swcrop;
- break;
- case OPT_SWDESPECK:
- *reinterpret_cast<SANE_Word*>(val) = s->swdespeck;
- break;
- case OPT_SWDEROTATE:
- *reinterpret_cast<SANE_Word*>(val) = s->swderotate;
- break;
- case OPT_SWSKIP:
- *reinterpret_cast<SANE_Word*>(val) = s->swskip;
- break;
- case OPT_DESPECK:
- *reinterpret_cast<SANE_Word*>(val) = s->despeck;
- break;
case OPT_CONTRAST:
*reinterpret_cast<SANE_Word*>(val) = s->contrast;
break;
@@ -5297,13 +5755,13 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
throw SaneException("Unsupported scanner mode selected");
table = reinterpret_cast<SANE_Word*>(val);
- if (s->color_filter == "Red") {
- gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_RED);
- } else if (s->color_filter == "Blue") {
- gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_BLUE);
- } else {
- gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_GREEN);
- }
+ if (s->color_filter == "Red") {
+ gamma_table = get_gamma_table(dev, *sensor, GENESYS_RED);
+ } else if (s->color_filter == "Blue") {
+ gamma_table = get_gamma_table(dev, *sensor, GENESYS_BLUE);
+ } else {
+ gamma_table = get_gamma_table(dev, *sensor, GENESYS_GREEN);
+ }
option_size = s->opt[option].size / sizeof (SANE_Word);
if (gamma_table.size() != option_size) {
throw std::runtime_error("The size of the gamma tables does not match");
@@ -5317,7 +5775,7 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
throw SaneException("Unsupported scanner mode selected");
table = reinterpret_cast<SANE_Word*>(val);
- gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_RED);
+ gamma_table = get_gamma_table(dev, *sensor, GENESYS_RED);
option_size = s->opt[option].size / sizeof (SANE_Word);
if (gamma_table.size() != option_size) {
throw std::runtime_error("The size of the gamma tables does not match");
@@ -5331,7 +5789,7 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
throw SaneException("Unsupported scanner mode selected");
table = reinterpret_cast<SANE_Word*>(val);
- gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_GREEN);
+ gamma_table = get_gamma_table(dev, *sensor, GENESYS_GREEN);
option_size = s->opt[option].size / sizeof (SANE_Word);
if (gamma_table.size() != option_size) {
throw std::runtime_error("The size of the gamma tables does not match");
@@ -5345,7 +5803,7 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
throw SaneException("Unsupported scanner mode selected");
table = reinterpret_cast<SANE_Word*>(val);
- gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_BLUE);
+ gamma_table = get_gamma_table(dev, *sensor, GENESYS_BLUE);
option_size = s->opt[option].size / sizeof (SANE_Word);
if (gamma_table.size() != option_size) {
throw std::runtime_error("The size of the gamma tables does not match");
@@ -5377,11 +5835,10 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
bool result = true;
- auto session = s->dev->cmd_set->calculate_scan_session(s->dev, *sensor,
- s->dev->settings);
+ auto session = dev->cmd_set->calculate_scan_session(dev, *sensor, dev->settings);
- for (auto& cache : s->dev->calibration_cache) {
- if (sanei_genesys_is_compatible_calibration(s->dev, session, &cache, false)) {
+ for (auto& cache : dev->calibration_cache) {
+ if (sanei_genesys_is_compatible_calibration(dev, session, &cache, false)) {
*reinterpret_cast<SANE_Bool*>(val) = SANE_FALSE;
}
}
@@ -5400,6 +5857,7 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
static void set_calibration_value(Genesys_Scanner* s, const char* val)
{
DBG_HELPER(dbg);
+ auto dev = s->dev;
std::string new_calib_path = val;
Genesys_Device::Calibration new_calibration;
@@ -5414,8 +5872,8 @@ static void set_calibration_value(Genesys_Scanner* s, const char* val)
return;
}
- s->dev->calibration_cache = std::move(new_calibration);
- s->dev->calib_file = new_calib_path;
+ dev->calibration_cache = std::move(new_calibration);
+ dev->calib_file = new_calib_path;
s->calibration_file = new_calib_path;
DBG(DBG_info, "%s: Calibration filename set to '%s':\n", __func__, new_calib_path.c_str());
}
@@ -5426,12 +5884,13 @@ static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int
DBG_HELPER_ARGS(dbg, "option: %s (%d)", s->opt[option].name, option);
print_option(dbg, *s, option, val);
+ auto* dev = s->dev;
+
SANE_Word *table;
unsigned int i;
unsigned option_size = 0;
- switch (option)
- {
+ switch (option) {
case OPT_TL_X:
s->pos_top_left_x = *reinterpret_cast<SANE_Word*>(val);
calc_parameters(s);
@@ -5457,46 +5916,6 @@ static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int
calc_parameters(s);
*myinfo |= SANE_INFO_RELOAD_PARAMS;
break;
- case OPT_THRESHOLD:
- s->threshold = *reinterpret_cast<SANE_Word*>(val);
- calc_parameters(s);
- *myinfo |= SANE_INFO_RELOAD_PARAMS;
- break;
- case OPT_THRESHOLD_CURVE:
- s->threshold_curve = *reinterpret_cast<SANE_Word*>(val);
- calc_parameters(s);
- *myinfo |= SANE_INFO_RELOAD_PARAMS;
- break;
- case OPT_SWCROP:
- s->swcrop = *reinterpret_cast<SANE_Word*>(val);
- calc_parameters(s);
- *myinfo |= SANE_INFO_RELOAD_PARAMS;
- break;
- case OPT_SWDESKEW:
- s->swdeskew = *reinterpret_cast<SANE_Word*>(val);
- calc_parameters(s);
- *myinfo |= SANE_INFO_RELOAD_PARAMS;
- break;
- case OPT_DESPECK:
- s->despeck = *reinterpret_cast<SANE_Word*>(val);
- calc_parameters(s);
- *myinfo |= SANE_INFO_RELOAD_PARAMS;
- break;
- case OPT_SWDEROTATE:
- s->swderotate = *reinterpret_cast<SANE_Word*>(val);
- calc_parameters(s);
- *myinfo |= SANE_INFO_RELOAD_PARAMS;
- break;
- case OPT_SWSKIP:
- s->swskip = *reinterpret_cast<SANE_Word*>(val);
- calc_parameters(s);
- *myinfo |= SANE_INFO_RELOAD_PARAMS;
- break;
- case OPT_DISABLE_INTERPOLATION:
- s->disable_interpolation = *reinterpret_cast<SANE_Word*>(val);
- calc_parameters(s);
- *myinfo |= SANE_INFO_RELOAD_PARAMS;
- break;
case OPT_LAMP_OFF:
s->lamp_off = *reinterpret_cast<SANE_Word*>(val);
calc_parameters(s);
@@ -5517,38 +5936,14 @@ static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int
calc_parameters(s);
*myinfo |= SANE_INFO_RELOAD_PARAMS;
break;
- case OPT_SWDESPECK:
- s->swdespeck = *reinterpret_cast<SANE_Word*>(val);
- if (s->swdespeck) {
- ENABLE(OPT_DESPECK);
- } else {
- DISABLE(OPT_DESPECK);
- }
- calc_parameters(s);
- *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
- break;
/* software enhancement functions only apply to 8 or 1 bits data */
case OPT_BIT_DEPTH:
s->bit_depth = *reinterpret_cast<SANE_Word*>(val);
if(s->bit_depth>8)
{
- DISABLE(OPT_SWDESKEW);
- DISABLE(OPT_SWDESPECK);
- DISABLE(OPT_SWCROP);
- DISABLE(OPT_DESPECK);
- DISABLE(OPT_SWDEROTATE);
- DISABLE(OPT_SWSKIP);
DISABLE(OPT_CONTRAST);
DISABLE(OPT_BRIGHTNESS);
- }
- else
- {
- ENABLE(OPT_SWDESKEW);
- ENABLE(OPT_SWDESPECK);
- ENABLE(OPT_SWCROP);
- ENABLE(OPT_DESPECK);
- ENABLE(OPT_SWDEROTATE);
- ENABLE(OPT_SWSKIP);
+ } else {
ENABLE(OPT_CONTRAST);
ENABLE(OPT_BRIGHTNESS);
}
@@ -5567,38 +5962,22 @@ static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int
}
break;
}
- case OPT_MODE:
- s->mode = reinterpret_cast<const char*>(val);
+ case OPT_MODE: {
+ s->mode = reinterpret_cast<const char*>(val);
- if (s->mode == SANE_VALUE_SCAN_MODE_LINEART)
- {
- ENABLE (OPT_THRESHOLD);
- ENABLE (OPT_THRESHOLD_CURVE);
- DISABLE (OPT_BIT_DEPTH);
- if (s->dev->model->asic_type != AsicType::GL646 || !s->dev->model->is_cis) {
+ if (s->mode == SANE_VALUE_SCAN_MODE_GRAY) {
+ if (dev->model->asic_type != AsicType::GL646 || !dev->model->is_cis) {
ENABLE(OPT_COLOR_FILTER);
}
- }
- else
- {
- DISABLE (OPT_THRESHOLD);
- DISABLE (OPT_THRESHOLD_CURVE);
- if (s->mode == SANE_VALUE_SCAN_MODE_GRAY)
- {
- if (s->dev->model->asic_type != AsicType::GL646 || !s->dev->model->is_cis) {
- ENABLE(OPT_COLOR_FILTER);
- }
- create_bpp_list (s, s->dev->model->bpp_gray_values);
- s->bit_depth = s->dev->model->bpp_gray_values[0];
- }
- else
- {
- DISABLE (OPT_COLOR_FILTER);
- create_bpp_list (s, s->dev->model->bpp_color_values);
- s->bit_depth = s->dev->model->bpp_color_values[0];
- }
- }
- calc_parameters(s);
+ create_bpp_list(s, dev->model->bpp_gray_values);
+ s->bit_depth = dev->model->bpp_gray_values[0];
+ } else {
+ DISABLE(OPT_COLOR_FILTER);
+ create_bpp_list(s, dev->model->bpp_color_values);
+ s->bit_depth = dev->model->bpp_color_values[0];
+ }
+
+ calc_parameters(s);
/* if custom gamma, toggle gamma table options according to the mode */
if (s->custom_gamma)
@@ -5621,30 +6000,31 @@ static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int
*myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
break;
+ }
case OPT_COLOR_FILTER:
s->color_filter = reinterpret_cast<const char*>(val);
calc_parameters(s);
break;
- case OPT_CALIBRATION_FILE:
- if (s->dev->force_calibration == 0) {
+ case OPT_CALIBRATION_FILE: {
+ if (dev->force_calibration == 0) {
set_calibration_value(s, reinterpret_cast<const char*>(val));
}
break;
- case OPT_LAMP_OFF_TIME:
- if (*reinterpret_cast<SANE_Word*>(val) != s->lamp_off_time) {
- s->lamp_off_time = *reinterpret_cast<SANE_Word*>(val);
- s->dev->cmd_set->set_powersaving(s->dev, s->lamp_off_time);
}
- break;
- case OPT_EXPIRATION_TIME:
- if (*reinterpret_cast<SANE_Word*>(val) != s->expiration_time) {
- s->expiration_time = *reinterpret_cast<SANE_Word*>(val);
- // BUG: this is most likely not intended behavior, found out during refactor
- s->dev->cmd_set->set_powersaving(s->dev, s->expiration_time);
- }
- break;
-
- case OPT_CUSTOM_GAMMA:
+ case OPT_LAMP_OFF_TIME: {
+ if (*reinterpret_cast<SANE_Word*>(val) != s->lamp_off_time) {
+ s->lamp_off_time = *reinterpret_cast<SANE_Word*>(val);
+ dev->cmd_set->set_powersaving(dev, s->lamp_off_time);
+ }
+ break;
+ }
+ case OPT_EXPIRATION_TIME: {
+ if (*reinterpret_cast<SANE_Word*>(val) != s->expiration_time) {
+ s->expiration_time = *reinterpret_cast<SANE_Word*>(val);
+ }
+ break;
+ }
+ case OPT_CUSTOM_GAMMA: {
*myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
s->custom_gamma = *reinterpret_cast<SANE_Bool*>(val);
@@ -5670,88 +6050,96 @@ static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int
DISABLE (OPT_GAMMA_VECTOR_R);
DISABLE (OPT_GAMMA_VECTOR_G);
DISABLE (OPT_GAMMA_VECTOR_B);
- for (auto& table : s->dev->gamma_override_tables) {
- table.clear();
+ for (auto& table : dev->gamma_override_tables) {
+ table.clear();
+ }
}
- }
- break;
-
- case OPT_GAMMA_VECTOR:
- table = reinterpret_cast<SANE_Word*>(val);
- option_size = s->opt[option].size / sizeof (SANE_Word);
+ break;
+ }
- s->dev->gamma_override_tables[GENESYS_RED].resize(option_size);
- s->dev->gamma_override_tables[GENESYS_GREEN].resize(option_size);
- s->dev->gamma_override_tables[GENESYS_BLUE].resize(option_size);
- for (i = 0; i < option_size; i++) {
- s->dev->gamma_override_tables[GENESYS_RED][i] = table[i];
- s->dev->gamma_override_tables[GENESYS_GREEN][i] = table[i];
- s->dev->gamma_override_tables[GENESYS_BLUE][i] = table[i];
+ case OPT_GAMMA_VECTOR: {
+ table = reinterpret_cast<SANE_Word*>(val);
+ option_size = s->opt[option].size / sizeof (SANE_Word);
+
+ dev->gamma_override_tables[GENESYS_RED].resize(option_size);
+ dev->gamma_override_tables[GENESYS_GREEN].resize(option_size);
+ dev->gamma_override_tables[GENESYS_BLUE].resize(option_size);
+ for (i = 0; i < option_size; i++) {
+ dev->gamma_override_tables[GENESYS_RED][i] = table[i];
+ dev->gamma_override_tables[GENESYS_GREEN][i] = table[i];
+ dev->gamma_override_tables[GENESYS_BLUE][i] = table[i];
+ }
+ break;
}
- break;
- case OPT_GAMMA_VECTOR_R:
- table = reinterpret_cast<SANE_Word*>(val);
- option_size = s->opt[option].size / sizeof (SANE_Word);
- s->dev->gamma_override_tables[GENESYS_RED].resize(option_size);
- for (i = 0; i < option_size; i++) {
- s->dev->gamma_override_tables[GENESYS_RED][i] = table[i];
+ case OPT_GAMMA_VECTOR_R: {
+ table = reinterpret_cast<SANE_Word*>(val);
+ option_size = s->opt[option].size / sizeof (SANE_Word);
+ dev->gamma_override_tables[GENESYS_RED].resize(option_size);
+ for (i = 0; i < option_size; i++) {
+ dev->gamma_override_tables[GENESYS_RED][i] = table[i];
+ }
+ break;
}
- break;
- case OPT_GAMMA_VECTOR_G:
- table = reinterpret_cast<SANE_Word*>(val);
- option_size = s->opt[option].size / sizeof (SANE_Word);
- s->dev->gamma_override_tables[GENESYS_GREEN].resize(option_size);
- for (i = 0; i < option_size; i++) {
- s->dev->gamma_override_tables[GENESYS_GREEN][i] = table[i];
+ case OPT_GAMMA_VECTOR_G: {
+ table = reinterpret_cast<SANE_Word*>(val);
+ option_size = s->opt[option].size / sizeof (SANE_Word);
+ dev->gamma_override_tables[GENESYS_GREEN].resize(option_size);
+ for (i = 0; i < option_size; i++) {
+ dev->gamma_override_tables[GENESYS_GREEN][i] = table[i];
+ }
+ break;
}
- break;
- case OPT_GAMMA_VECTOR_B:
- table = reinterpret_cast<SANE_Word*>(val);
- option_size = s->opt[option].size / sizeof (SANE_Word);
- s->dev->gamma_override_tables[GENESYS_BLUE].resize(option_size);
- for (i = 0; i < option_size; i++) {
- s->dev->gamma_override_tables[GENESYS_BLUE][i] = table[i];
+ case OPT_GAMMA_VECTOR_B: {
+ table = reinterpret_cast<SANE_Word*>(val);
+ option_size = s->opt[option].size / sizeof (SANE_Word);
+ dev->gamma_override_tables[GENESYS_BLUE].resize(option_size);
+ for (i = 0; i < option_size; i++) {
+ dev->gamma_override_tables[GENESYS_BLUE][i] = table[i];
+ }
+ break;
}
- break;
case OPT_CALIBRATE: {
- auto& sensor = sanei_genesys_find_sensor_for_write(s->dev, s->dev->settings.xres,
- s->dev->settings.get_channels(),
- s->dev->settings.scan_method);
+ auto& sensor = sanei_genesys_find_sensor_for_write(dev, dev->settings.xres,
+ dev->settings.get_channels(),
+ dev->settings.scan_method);
catch_all_exceptions(__func__, [&]()
{
- s->dev->cmd_set->save_power(s->dev, false);
- genesys_scanner_calibration(s->dev, sensor);
+ dev->cmd_set->save_power(dev, false);
+ genesys_scanner_calibration(dev, sensor);
});
catch_all_exceptions(__func__, [&]()
{
- s->dev->cmd_set->save_power(s->dev, true);
+ dev->cmd_set->save_power(dev, true);
});
*myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
break;
}
- case OPT_CLEAR_CALIBRATION:
- s->dev->calibration_cache.clear();
+ case OPT_CLEAR_CALIBRATION: {
+ dev->calibration_cache.clear();
- /* remove file */
- unlink(s->dev->calib_file.c_str());
- /* signals that sensors will have to be read again */
- *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
- break;
- case OPT_FORCE_CALIBRATION:
- s->dev->force_calibration = 1;
- s->dev->calibration_cache.clear();
- s->dev->calib_file.clear();
+ // remove file
+ unlink(dev->calib_file.c_str());
+ // signals that sensors will have to be read again
+ *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
+ break;
+ }
+ case OPT_FORCE_CALIBRATION: {
+ dev->force_calibration = 1;
+ dev->calibration_cache.clear();
+ dev->calib_file.clear();
- /* signals that sensors will have to be read again */
- *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
- break;
+ // signals that sensors will have to be read again
+ *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
+ break;
+ }
case OPT_IGNORE_OFFSETS: {
- s->dev->ignore_offsets = true;
+ dev->ignore_offsets = true;
break;
}
- default:
- DBG(DBG_warn, "%s: can't set unknown option %d\n", __func__, option);
+ default: {
+ DBG(DBG_warn, "%s: can't set unknown option %d\n", __func__, option);
+ }
}
}
@@ -5829,13 +6217,13 @@ void sane_get_parameters_impl(SANE_Handle handle, SANE_Parameters* params)
{
DBG_HELPER(dbg);
Genesys_Scanner* s = reinterpret_cast<Genesys_Scanner*>(handle);
+ auto* dev = s->dev;
/* don't recompute parameters once data reading is active, ie during scan */
- if (!s->dev->read_active) {
+ if (!dev->read_active) {
calc_parameters(s);
}
- if (params)
- {
+ if (params) {
*params = s->params;
/* in the case of a sheetfed scanner, when full height is specified
@@ -5843,11 +6231,11 @@ void sane_get_parameters_impl(SANE_Handle handle, SANE_Parameters* params)
* don't know the real document height.
* We don't do that doing buffering image for digital processing
*/
- if (s->dev->model->is_sheetfed && !s->dev->buffer_image &&
+ if (dev->model->is_sheetfed &&
s->pos_bottom_right_y == s->opt[OPT_BR_Y].constraint.range->max)
{
- params->lines = -1;
- }
+ params->lines = -1;
+ }
}
debug_dump(DBG_proc, *params);
}
@@ -5865,6 +6253,7 @@ void sane_start_impl(SANE_Handle handle)
{
DBG_HELPER(dbg);
Genesys_Scanner* s = reinterpret_cast<Genesys_Scanner*>(handle);
+ auto* dev = s->dev;
if (s->pos_top_left_x >= s->pos_bottom_right_x) {
throw SaneException("top left x >= bottom right x");
@@ -5873,67 +6262,27 @@ void sane_start_impl(SANE_Handle handle)
throw SaneException("top left y >= bottom right y");
}
- /* First make sure we have a current parameter set. Some of the
- parameters will be overwritten below, but that's OK. */
-
- calc_parameters(s);
- genesys_start_scan(s->dev, s->lamp_off);
-
- s->scanning = true;
+ // fetch stored calibration
+ if (dev->force_calibration == 0) {
+ auto path = calibration_filename(dev);
+ s->calibration_file = path;
+ dev->calib_file = path;
+ DBG(DBG_info, "%s: Calibration filename set to:\n", __func__);
+ DBG(DBG_info, "%s: >%s<\n", __func__, dev->calib_file.c_str());
- /* allocate intermediate buffer when doing dynamic lineart */
- if (s->dev->settings.scan_mode == ScanColorMode::LINEART) {
- s->dev->binarize_buffer.clear();
- s->dev->binarize_buffer.alloc(s->dev->settings.pixels);
- s->dev->local_buffer.clear();
- s->dev->local_buffer.alloc(s->dev->binarize_buffer.size() * 8);
+ catch_all_exceptions(__func__, [&]()
+ {
+ sanei_genesys_read_calibration(dev->calibration_cache, dev->calib_file);
+ });
}
- /* if one of the software enhancement option is selected,
- * we do the scan internally, process picture then put it an internal
- * buffer. Since cropping may change scan parameters, we recompute them
- * at the end */
- if (s->dev->buffer_image)
- {
- genesys_buffer_image(s);
-
- /* check if we need to skip this page, sheetfed scanners
- * can go to next doc while flatbed ones can't */
- if (s->swskip > 0 && IS_ACTIVE(OPT_SWSKIP)) {
- auto status = sanei_magic_isBlank(&s->params,
- s->dev->img_buffer.data(),
- SANE_UNFIX(s->swskip));
-
- if (status == SANE_STATUS_NO_DOCS && s->dev->model->is_sheetfed) {
- DBG(DBG_info, "%s: blank page, recurse\n", __func__);
- sane_start(handle);
- return;
- }
+ // First make sure we have a current parameter set. Some of the
+ // parameters will be overwritten below, but that's OK.
- if (status != SANE_STATUS_GOOD) {
- throw SaneException(status);
- }
- }
-
- if (s->swdeskew) {
- const auto& sensor = sanei_genesys_find_sensor(s->dev, s->dev->settings.xres,
- s->dev->settings.get_channels(),
- s->dev->settings.scan_method);
- catch_all_exceptions(__func__, [&](){ genesys_deskew(s, sensor); });
- }
-
- if (s->swdespeck) {
- catch_all_exceptions(__func__, [&](){ genesys_despeck(s); });
- }
-
- if(s->swcrop) {
- catch_all_exceptions(__func__, [&](){ genesys_crop(s); });
- }
+ calc_parameters(s);
+ genesys_start_scan(dev, s->lamp_off);
- if(s->swderotate) {
- catch_all_exceptions(__func__, [&](){ genesys_derotate(s); });
- }
- }
+ s->scanning = true;
}
SANE_GENESYS_API_LINKAGE
@@ -5945,18 +6294,18 @@ SANE_Status sane_start(SANE_Handle handle)
});
}
-void sane_read_impl(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int* len)
+// returns SANE_STATUS_GOOD if there are more data, SANE_STATUS_EOF otherwise
+SANE_Status sane_read_impl(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int* len)
{
DBG_HELPER(dbg);
Genesys_Scanner* s = reinterpret_cast<Genesys_Scanner*>(handle);
- Genesys_Device *dev;
size_t local_len;
if (!s) {
throw SaneException("handle is nullptr");
}
- dev=s->dev;
+ auto* dev = s->dev;
if (!dev) {
throw SaneException("dev is nullptr");
}
@@ -5986,86 +6335,33 @@ void sane_read_impl(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_
/* issue park command immediatly in case scanner can handle it
* so we save time */
- if (!dev->model->is_sheetfed && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) &&
+ if (!dev->model->is_sheetfed && !has_flag(dev->model->flags, ModelFlag::MUST_WAIT) &&
!dev->parking)
{
dev->cmd_set->move_back_home(dev, false);
dev->parking = true;
}
- throw SaneException(SANE_STATUS_EOF);
+ return SANE_STATUS_EOF;
}
local_len = max_len;
- /* in case of image processing, all data has been stored in
- * buffer_image. So read data from it if it exists, else from scanner */
- if(!dev->buffer_image)
- {
- /* dynamic lineart is another kind of digital processing that needs
- * another layer of buffering on top of genesys_read_ordered_data */
- if (dev->settings.scan_mode == ScanColorMode::LINEART) {
- /* if buffer is empty, fill it with genesys_read_ordered_data */
- if(dev->binarize_buffer.avail() == 0)
- {
- /* store gray data */
- local_len=dev->local_buffer.size();
- dev->local_buffer.reset();
- genesys_read_ordered_data(dev, dev->local_buffer.get_write_pos(local_len),
- &local_len);
- dev->local_buffer.produce(local_len);
-
- dev->binarize_buffer.reset();
- if (!is_testing_mode()) {
- genesys_gray_lineart(dev, dev->local_buffer.get_read_pos(),
- dev->binarize_buffer.get_write_pos(local_len / 8),
- dev->settings.pixels,
- local_len / dev->settings.pixels,
- dev->settings.threshold);
- }
- dev->binarize_buffer.produce(local_len / 8);
- }
-
- /* return data from lineart buffer if any, up to the available amount */
- local_len = max_len;
- if (static_cast<std::size_t>(max_len) > dev->binarize_buffer.avail())
- {
- local_len=dev->binarize_buffer.avail();
- }
- if(local_len)
- {
- memcpy(buf, dev->binarize_buffer.get_read_pos(), local_len);
- dev->binarize_buffer.consume(local_len);
- }
- }
- else
- {
- // most usual case, direct read of data from scanner */
- genesys_read_ordered_data(dev, buf, &local_len);
- }
- }
- else /* read data from buffer */
- {
- if(dev->total_bytes_read+local_len>dev->total_bytes_to_read)
- {
- local_len=dev->total_bytes_to_read-dev->total_bytes_read;
- }
- memcpy(buf, dev->img_buffer.data() + dev->total_bytes_read, local_len);
- dev->total_bytes_read+=local_len;
- }
+ genesys_read_ordered_data(dev, buf, &local_len);
*len = local_len;
if (local_len > static_cast<std::size_t>(max_len)) {
- fprintf (stderr, "[genesys] sane_read: returning incorrect length!!\n");
+ dbg.log(DBG_error, "error: returning incorrect length");
}
DBG(DBG_proc, "%s: %d bytes returned\n", __func__, *len);
+ return SANE_STATUS_GOOD;
}
SANE_GENESYS_API_LINKAGE
SANE_Status sane_read(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int* len)
{
- return wrap_exceptions_to_status_code(__func__, [=]()
+ return wrap_exceptions_to_status_code_return(__func__, [=]()
{
- sane_read_impl(handle, buf, max_len, len);
+ return sane_read_impl(handle, buf, max_len, len);
});
}
@@ -6073,36 +6369,31 @@ void sane_cancel_impl(SANE_Handle handle)
{
DBG_HELPER(dbg);
Genesys_Scanner* s = reinterpret_cast<Genesys_Scanner*>(handle);
+ auto* dev = s->dev;
s->scanning = false;
- s->dev->read_active = false;
- s->dev->img_buffer.clear();
+ dev->read_active = false;
- /* no need to end scan if we are parking the head */
- if (!s->dev->parking) {
- s->dev->cmd_set->end_scan(s->dev, &s->dev->reg, true);
+ // no need to end scan if we are parking the head
+ if (!dev->parking) {
+ dev->cmd_set->end_scan(dev, &dev->reg, true);
}
- /* park head if flatbed scanner */
- if (!s->dev->model->is_sheetfed) {
- if (!s->dev->parking) {
- s->dev->cmd_set->move_back_home (s->dev, s->dev->model->flags &
- GENESYS_FLAG_MUST_WAIT);
-
- s->dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT);
+ // park head if flatbed scanner
+ if (!dev->model->is_sheetfed) {
+ if (!dev->parking) {
+ dev->cmd_set->move_back_home(dev, has_flag(dev->model->flags, ModelFlag::MUST_WAIT));
+ dev->parking = !has_flag(dev->model->flags, ModelFlag::MUST_WAIT);
}
- }
- else
- { /* in case of sheetfed scanners, we have to eject the document if still present */
- s->dev->cmd_set->eject_document(s->dev);
+ } else {
+ // in case of sheetfed scanners, we have to eject the document if still present
+ dev->cmd_set->eject_document(dev);
}
- /* enable power saving mode unless we are parking .... */
- if (!s->dev->parking) {
- s->dev->cmd_set->save_power(s->dev, true);
+ // enable power saving mode unless we are parking ....
+ if (!dev->parking) {
+ dev->cmd_set->save_power(dev, true);
}
-
- return;
}
SANE_GENESYS_API_LINKAGE
diff --git a/backend/genesys/genesys.h b/backend/genesys/genesys.h
index 255bf76..9b1a087 100644
--- a/backend/genesys/genesys.h
+++ b/backend/genesys/genesys.h
@@ -107,21 +107,12 @@ enum Genesys_Option
OPT_GAMMA_VECTOR_R,
OPT_GAMMA_VECTOR_G,
OPT_GAMMA_VECTOR_B,
- OPT_SWDESKEW,
- OPT_SWCROP,
- OPT_SWDESPECK,
- OPT_DESPECK,
- OPT_SWSKIP,
- OPT_SWDEROTATE,
OPT_BRIGHTNESS,
OPT_CONTRAST,
OPT_EXTRAS_GROUP,
OPT_LAMP_OFF_TIME,
OPT_LAMP_OFF,
- OPT_THRESHOLD,
- OPT_THRESHOLD_CURVE,
- OPT_DISABLE_INTERPOLATION,
OPT_COLOR_FILTER,
OPT_CALIBRATION_FILE,
OPT_EXPIRATION_TIME,
@@ -213,18 +204,9 @@ struct Genesys_Scanner
// Option values
SANE_Word bit_depth = 0;
SANE_Word resolution = 0;
- bool preview = false;
- SANE_Word threshold = 0;
- SANE_Word threshold_curve = 0;
- bool disable_interpolation = false;
+ bool preview = false; // TODO: currently not used
bool lamp_off = false;
SANE_Word lamp_off_time = 0;
- bool swdeskew = false;
- bool swcrop = false;
- bool swdespeck = false;
- bool swderotate = false;
- SANE_Word swskip = 0;
- SANE_Word despeck = 0;
SANE_Word contrast = 0;
SANE_Word brightness = 0;
SANE_Word expiration_time = 0;
diff --git a/backend/genesys/gl124.cpp b/backend/genesys/gl124.cpp
index 054f1ef..d3fc1bc 100644
--- a/backend/genesys/gl124.cpp
+++ b/backend/genesys/gl124.cpp
@@ -53,6 +53,37 @@
namespace genesys {
namespace gl124 {
+struct Gpio_layout
+{
+ std::uint8_t r31;
+ std::uint8_t r32;
+ std::uint8_t r33;
+ std::uint8_t r34;
+ std::uint8_t r35;
+ std::uint8_t r36;
+ std::uint8_t r38;
+};
+
+/** @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
+ },
+};
+
+
/** @brief set all registers to default values .
* This function is called only once at the beginning and
* fills register startup values for registers reused across scans.
@@ -336,54 +367,9 @@ gl124_init_registers (Genesys_Device * dev)
// fine tune upon device description
const auto& sensor = sanei_genesys_find_sensor_any(dev);
- sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res);
-
- dev->calib_reg = dev->reg;
-}
-
-/**@brief send slope table for motor movement
- * Send slope_table in machine byte order
- * @param dev device to send slope table
- * @param table_nr index of the slope table in ASIC memory
- * Must be in the [0-4] range.
- * @param slope_table pointer to 16 bit values array of the slope table
- * @param steps number of elemnts in the slope table
- */
-static void gl124_send_slope_table(Genesys_Device* dev, int table_nr,
- const std::vector<uint16_t>& slope_table,
- int steps)
-{
- DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps);
- int i;
- char msg[10000];
-
- /* sanity check */
- if(table_nr<0 || table_nr>4)
- {
- throw SaneException("invalid table number");
- }
-
- std::vector<uint8_t> table(steps * 2);
- for (i = 0; i < steps; i++)
- {
- table[i * 2] = slope_table[i] & 0xff;
- table[i * 2 + 1] = slope_table[i] >> 8;
- }
-
- if (DBG_LEVEL >= DBG_io)
- {
- std::sprintf(msg, "write slope %d (%d)=", table_nr, steps);
- for (i = 0; i < steps; i++) {
- std::sprintf(msg + std::strlen(msg), ",%d", slope_table[i]);
- }
- DBG (DBG_io, "%s: %s\n", __func__, msg);
- }
-
- if (dev->interface->is_mock()) {
- dev->interface->record_slope_table(table_nr, slope_table);
- }
- // slope table addresses are fixed
- dev->interface->write_ahb(0x10000000 + 0x4000 * table_nr, steps * 2, table.data());
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, sensor.full_resolution,
+ 3, ScanMethod::FLATBED);
+ sanei_genesys_set_dpihw(dev->reg, dpihw_sensor.register_dpihw);
}
/** @brief * Set register values of 'special' ti type frontend
@@ -397,12 +383,8 @@ static void gl124_set_ti_fe(Genesys_Device* dev, uint8_t set)
DBG_HELPER(dbg);
int i;
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s: setting DAC %u\n", __func__,
- static_cast<unsigned>(dev->model->adc_id));
-
- dev->frontend = dev->frontend_initial;
+ if (set == AFE_INIT) {
+ dev->frontend = dev->frontend_initial;
}
// start writing to DAC
@@ -441,11 +423,8 @@ void CommandSetGl124::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
(void) sensor;
uint8_t val;
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s(): setting DAC %u\n", __func__,
- static_cast<unsigned>(dev->model->adc_id));
- dev->frontend = dev->frontend_initial;
+ if (set == AFE_INIT) {
+ dev->frontend = dev->frontend_initial;
}
val = dev->interface->read_register(REG_0x0A);
@@ -466,14 +445,14 @@ void CommandSetGl124::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
static void gl124_init_motor_regs_scan(Genesys_Device* dev,
const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
- const Motor_Profile& motor_profile,
+ const MotorProfile& motor_profile,
unsigned int scan_exposure_time,
unsigned scan_yres,
unsigned int scan_lines,
unsigned int scan_dummy,
unsigned int feed_steps,
ScanColorMode scan_mode,
- MotorFlag flags)
+ ScanFlag flags)
{
DBG_HELPER(dbg);
int use_fast_fed;
@@ -533,11 +512,8 @@ static void gl124_init_motor_regs_scan(Genesys_Device* dev,
linesel=0;
}
- DBG(DBG_io2, "%s: final yres=%d, linesel=%d\n", __func__, yres, linesel);
-
lincnt=scan_lines*(linesel+1);
reg->set24(REG_LINCNT, lincnt);
- DBG (DBG_io, "%s: lincnt=%d\n", __func__, lincnt);
/* compute register 02 value */
uint8_t r02 = REG_0x02_NOTHOME;
@@ -548,15 +524,15 @@ static void gl124_init_motor_regs_scan(Genesys_Device* dev,
r02 &= ~REG_0x02_FASTFED;
}
- if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) {
+ if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
r02 |= REG_0x02_AGOHOME;
}
- if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE) || (yres >= sensor.optical_res))
+ if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) || (yres >= sensor.full_resolution))
{
r02 |= REG_0x02_ACDCDIS;
}
- if (has_flag(flags, MotorFlag::REVERSE)) {
+ if (has_flag(flags, ScanFlag::REVERSE)) {
r02 |= REG_0x02_MTRREV;
}
@@ -566,13 +542,12 @@ static void gl124_init_motor_regs_scan(Genesys_Device* dev,
reg->set16(REG_SCANFED, 4);
/* scan and backtracking slope table */
- auto scan_table = sanei_genesys_slope_table(dev->model->asic_type, yres, scan_exposure_time,
- dev->motor.base_ydpi, 1,
- motor_profile);
- gl124_send_slope_table(dev, SCAN_TABLE, scan_table.table, scan_table.steps_count);
- gl124_send_slope_table(dev, BACKTRACK_TABLE, scan_table.table, scan_table.steps_count);
+ auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, yres,
+ scan_exposure_time, 1, motor_profile);
+ scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table);
+ scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table);
- reg->set16(REG_STEPNO, scan_table.steps_count);
+ reg->set16(REG_STEPNO, scan_table.table.size());
/* fast table */
fast_dpi=yres;
@@ -583,28 +558,26 @@ static void gl124_init_motor_regs_scan(Genesys_Device* dev,
fast_dpi*=3;
}
*/
- auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_dpi,
- scan_exposure_time, dev->motor.base_ydpi,
- 1, motor_profile);
- gl124_send_slope_table(dev, STOP_TABLE, fast_table.table, fast_table.steps_count);
- gl124_send_slope_table(dev, FAST_TABLE, fast_table.table, fast_table.steps_count);
+ auto fast_table = create_slope_table(dev->model->asic_type, dev->motor, fast_dpi,
+ scan_exposure_time, 1, motor_profile);
+ scanner_send_slope_table(dev, sensor, STOP_TABLE, fast_table.table);
+ scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table);
- reg->set16(REG_FASTNO, fast_table.steps_count);
- reg->set16(REG_FSHDEC, fast_table.steps_count);
- reg->set16(REG_FMOVNO, fast_table.steps_count);
+ reg->set16(REG_FASTNO, fast_table.table.size());
+ reg->set16(REG_FSHDEC, fast_table.table.size());
+ reg->set16(REG_FMOVNO, fast_table.table.size());
/* substract acceleration distance from feedl */
feedl=feed_steps;
feedl <<= static_cast<unsigned>(motor_profile.step_type);
- dist = scan_table.steps_count;
- if (has_flag(flags, MotorFlag::FEED)) {
+ dist = scan_table.table.size();
+ if (has_flag(flags, ScanFlag::FEEDING)) {
dist *= 2;
}
if (use_fast_fed) {
- dist += fast_table.steps_count * 2;
+ dist += fast_table.table.size() * 2;
}
- DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist);
/* get sure we don't use insane value */
if (dist < feedl) {
@@ -614,160 +587,97 @@ static void gl124_init_motor_regs_scan(Genesys_Device* dev,
}
reg->set24(REG_FEEDL, feedl);
- DBG (DBG_io, "%s: feedl=%d\n", __func__, feedl);
/* doesn't seem to matter that much */
sanei_genesys_calculate_zmod(use_fast_fed,
scan_exposure_time,
scan_table.table,
- scan_table.steps_count,
+ scan_table.table.size(),
feedl,
- scan_table.steps_count,
+ scan_table.table.size(),
&z1,
&z2);
reg->set24(REG_Z1MOD, z1);
- DBG(DBG_info, "%s: z1 = %d\n", __func__, z1);
-
reg->set24(REG_Z2MOD, z2);
- DBG(DBG_info, "%s: z2 = %d\n", __func__, z2);
/* LINESEL */
reg->set8_mask(REG_0x1D, linesel, REG_0x1D_LINESEL);
reg->set8(REG_0xA0, (static_cast<unsigned>(motor_profile.step_type) << REG_0xA0S_STEPSEL) |
(static_cast<unsigned>(motor_profile.step_type) << REG_0xA0S_FSTPSEL));
- reg->set16(REG_FMOVDEC, fast_table.steps_count);
+ reg->set16(REG_FMOVDEC, fast_table.table.size());
}
-
-/** @brief copy sensor specific settings
- * Set up register set for the given sensor resolution. Values are from the device table
- * in genesys_devices.c for registers:
- * [0x16 ... 0x1d]
- * [0x52 ... 0x5e]
- * Other come from the specific device sensor table in genesys_gl124.h:
- * 0x18, 0x20, 0x61, 0x98 and
- * @param dev device to set up
- * @param regs register set to modify
- * @param dpi resolution of the sensor during scan
- * @param ccd_size_divisor flag for half ccd mode
- * */
-static void gl124_setup_sensor(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs)
-{
- DBG_HELPER(dbg);
-
- for (const auto& reg : sensor.custom_regs) {
- regs->set8(reg.address, reg.value);
- }
-
- regs->set24(REG_EXPR, sensor.exposure.red);
- regs->set24(REG_EXPG, sensor.exposure.green);
- regs->set24(REG_EXPB, sensor.exposure.blue);
-
- dev->segment_order = sensor.segment_order;
-}
-
-/** @brief setup optical related registers
- * start and pixels are expressed in optical sensor resolution coordinate
- * space.
- * @param dev scanner device to use
- * @param reg registers to set up
- * @param exposure_time exposure time to use
- * @param used_res scanning resolution used, may differ from
- * scan's one
- * @param start logical start pixel coordinate
- * @param pixels logical number of pixels to use
- * @param channels number of color channels (currently 1 or 3)
- * @param depth bit depth of the scan (1, 8 or 16)
- * @param ccd_size_divisor whether sensor's timings are such that x coordinates must be halved
- * @param color_filter color channel to use as gray data
- * @param flags optical flags (@see )
- */
static void gl124_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg, unsigned int exposure_time,
const ScanSession& session)
{
DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time);
- unsigned int dpihw;
- GenesysRegister *r;
uint32_t expmax;
- // resolution is divided according to ccd_pixels_per_system_pixel
- unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel();
- DBG(DBG_io2, "%s: ccd_pixels_per_system_pixel=%d\n", __func__, ccd_pixels_per_system_pixel);
-
- // to manage high resolution device while keeping good low resolution scanning speed, we
- // make hardware dpi vary
- dpihw = sensor.get_register_hwdpi(session.output_resolution * ccd_pixels_per_system_pixel);
- DBG(DBG_io2, "%s: dpihw=%d\n", __func__, dpihw);
-
- gl124_setup_sensor(dev, sensor, reg);
+ scanner_setup_sensor(*dev, sensor, *reg);
dev->cmd_set->set_fe(dev, sensor, AFE_SET);
/* enable shading */
regs_set_optical_off(dev->model->asic_type, *reg);
- r = sanei_genesys_get_address (reg, REG_0x01);
if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
- (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION))
+ has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION))
{
- r->value &= ~REG_0x01_DVDSET;
+ reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET;
} else {
- r->value |= REG_0x01_DVDSET;
+ reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET;
}
- r = sanei_genesys_get_address(reg, REG_0x03);
if ((dev->model->sensor_id != SensorId::CIS_CANON_LIDE_120) && (session.params.xres>=600)) {
- r->value &= ~REG_0x03_AVEENB;
- DBG (DBG_io, "%s: disabling AVEENB\n", __func__);
- }
- else
- {
- r->value |= ~REG_0x03_AVEENB;
- DBG (DBG_io, "%s: enabling AVEENB\n", __func__);
+ reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB;
+ } else {
+ // BUG: the following is likely incorrect
+ reg->find_reg(REG_0x03).value |= ~REG_0x03_AVEENB;
}
sanei_genesys_set_lamp_power(dev, sensor, *reg,
!has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
// BW threshold
- dev->interface->write_register(REG_0x114, dev->settings.threshold);
- dev->interface->write_register(REG_0x115, dev->settings.threshold);
+ dev->interface->write_register(REG_0x114, 0x7f);
+ dev->interface->write_register(REG_0x115, 0x7f);
/* monochrome / color scan */
- r = sanei_genesys_get_address (reg, REG_0x04);
switch (session.params.depth) {
case 8:
- r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
+ reg->find_reg(REG_0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
break;
case 16:
- r->value &= ~REG_0x04_LINEART;
- r->value |= REG_0x04_BITSET;
+ reg->find_reg(REG_0x04).value &= ~REG_0x04_LINEART;
+ reg->find_reg(REG_0x04).value |= REG_0x04_BITSET;
break;
}
- r->value &= ~REG_0x04_FILTER;
+ reg->find_reg(REG_0x04).value &= ~REG_0x04_FILTER;
if (session.params.channels == 1)
{
switch (session.params.color_filter)
{
case ColorFilter::RED:
- r->value |= 0x10;
+ reg->find_reg(REG_0x04).value |= 0x10;
break;
case ColorFilter::BLUE:
- r->value |= 0x30;
+ reg->find_reg(REG_0x04).value |= 0x30;
break;
case ColorFilter::GREEN:
- r->value |= 0x20;
+ reg->find_reg(REG_0x04).value |= 0x20;
break;
default:
break; // should not happen
}
}
- sanei_genesys_set_dpihw(*reg, sensor, dpihw);
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution,
+ session.params.channels,
+ session.params.scan_method);
+ sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw);
if (should_enable_gamma(session, sensor)) {
reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
@@ -775,25 +685,16 @@ static void gl124_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB;
}
- unsigned dpiset_reg = session.output_resolution * ccd_pixels_per_system_pixel *
- session.ccd_size_divisor;
- if (sensor.dpiset_override != 0) {
- dpiset_reg = sensor.dpiset_override;
- }
-
- reg->set16(REG_DPISET, dpiset_reg);
- DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset_reg);
+ reg->set16(REG_DPISET, sensor.register_dpiset);
- r = sanei_genesys_get_address(reg, REG_0x06);
- r->value |= REG_0x06_GAIN4;
+ reg->find_reg(REG_0x06).value |= REG_0x06_GAIN4;
/* CIS scanners can do true gray by setting LEDADD */
/* we set up LEDADD only when asked */
if (dev->model->is_cis) {
- r = sanei_genesys_get_address (reg, REG_0x60);
- r->value &= ~REG_0x60_LEDADD;
+ reg->find_reg(REG_0x60).value &= ~REG_0x60_LEDADD;
if (session.enable_ledadd) {
- r->value |= REG_0x60_LEDADD;
+ reg->find_reg(REG_0x60).value |= REG_0x60_LEDADD;
expmax = reg->get24(REG_EXPR);
expmax = std::max(expmax, reg->get24(REG_EXPG));
expmax = std::max(expmax, reg->get24(REG_EXPB));
@@ -803,31 +704,32 @@ static void gl124_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
dev->reg.set24(REG_EXPB, expmax);
}
/* RGB weighting, REG_TRUER,G and B are to be set */
- r = sanei_genesys_get_address (reg, 0x01);
- r->value &= ~REG_0x01_TRUEGRAY;
+ reg->find_reg(0x01).value &= ~REG_0x01_TRUEGRAY;
if (session.enable_ledadd) {
- r->value |= REG_0x01_TRUEGRAY;
+ reg->find_reg(0x01).value |= REG_0x01_TRUEGRAY;
dev->interface->write_register(REG_TRUER, 0x80);
dev->interface->write_register(REG_TRUEG, 0x80);
dev->interface->write_register(REG_TRUEB, 0x80);
}
}
+ std::uint32_t pixel_endx = session.pixel_endx;
+ if (pixel_endx == reg->get24(REG_SEGCNT)) {
+ pixel_endx = 0;
+ }
reg->set24(REG_STRPIXEL, session.pixel_startx);
- reg->set24(REG_ENDPIXEL, session.pixel_endx);
+ reg->set24(REG_ENDPIXEL, pixel_endx);
dev->line_count = 0;
- build_image_pipeline(dev, session);
+ setup_image_pipeline(*dev, session);
// MAXWD is expressed in 2 words unit
// BUG: we shouldn't multiply by channels here
- reg->set24(REG_MAXWD, session.output_line_bytes_raw / session.ccd_size_divisor * session.params.channels);
-
+ reg->set24(REG_MAXWD, session.output_line_bytes_raw * session.params.channels *
+ session.optical_resolution / session.full_resolution);
reg->set24(REG_LPERIOD, exposure_time);
- DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time);
-
reg->set16(REG_DUMMY, sensor.dummy_pixel);
}
@@ -838,7 +740,6 @@ void CommandSetGl124::init_regs_for_scan_session(Genesys_Device* dev, const Gene
DBG_HELPER(dbg);
session.assert_computed();
- int move;
int exposure_time;
int dummy = 0;
@@ -856,9 +757,7 @@ void CommandSetGl124::init_regs_for_scan_session(Genesys_Device* dev, const Gene
} else {
exposure_time = sensor.exposure_lperiod;
}
- const auto& motor_profile = sanei_genesys_get_motor_profile(*gl124_motor_profiles,
- dev->model->motor_id,
- exposure_time);
+ const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure_time, session);
DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time);
DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, static_cast<unsigned>(motor_profile.step_type));
@@ -870,30 +769,13 @@ void CommandSetGl124::init_regs_for_scan_session(Genesys_Device* dev, const Gene
// now _LOGICAL_ optical values used are known, setup registers
gl124_init_optical_regs_scan(dev, sensor, reg, exposure_time, session);
- /* add tl_y to base movement */
- move = session.params.starty;
- DBG(DBG_info, "%s: move=%d steps\n", __func__, move);
-
- MotorFlag mflags = MotorFlag::NONE;
- if (has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) {
- mflags |= MotorFlag::DISABLE_BUFFER_FULL_MOVE;
- }
- if (has_flag(session.params.flags, ScanFlag::FEEDING)) {
- mflags |= MotorFlag::FEED;
- }
- if (has_flag(session.params.flags, ScanFlag::REVERSE)) {
- mflags |= MotorFlag::REVERSE;
- }
gl124_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure_time, slope_dpi,
- dev->model->is_cis ? session.output_line_count * session.params.channels :
- session.output_line_count,
- dummy, move, session.params.scan_mode, mflags);
+ session.optical_line_count,
+ dummy, session.params.starty, session.params.scan_mode,
+ session.params.flags);
/*** prepares data reordering ***/
- dev->read_buffer.clear();
- dev->read_buffer.alloc(session.buffer_size_read);
-
dev->read_active = true;
dev->session = session;
@@ -909,21 +791,24 @@ ScanSession CommandSetGl124::calculate_scan_session(const Genesys_Device* dev,
const Genesys_Sensor& sensor,
const Genesys_Settings& settings) const
{
- int start;
-
DBG(DBG_info, "%s ", __func__);
debug_dump(DBG_info, settings);
- /* start */
- start = static_cast<int>(dev->model->x_offset);
- start += static_cast<int>(settings.tl_x);
- start = static_cast<int>((start * sensor.optical_res) / MM_PER_INCH);
+ unsigned move_dpi = dev->motor.base_ydpi / 4;
+ float move = dev->model->y_offset;
+ move += dev->settings.tl_y;
+ move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
+
+ float start = dev->model->x_offset;
+ start += settings.tl_x;
+ start /= sensor.full_resolution / sensor.get_optical_resolution();
+ start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
ScanSession session;
session.params.xres = settings.xres;
session.params.yres = settings.yres;
- session.params.startx = start;
- session.params.starty = 0; // not used
+ session.params.startx = static_cast<unsigned>(start);
+ session.params.starty = static_cast<unsigned>(move);
session.params.pixels = settings.pixels;
session.params.requested_pixels = settings.requested_pixels;
session.params.lines = settings.lines;
@@ -953,17 +838,15 @@ void CommandSetGl124::save_power(Genesys_Device* dev, bool enable) const
void CommandSetGl124::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const
{
DBG_HELPER_ARGS(dbg, "delay = %d", delay);
- GenesysRegister *r;
- r = sanei_genesys_get_address(&dev->reg, REG_0x03);
- r->value &= ~0xf0;
+ dev->reg.find_reg(REG_0x03).value &= ~0xf0;
if(delay<15)
{
- r->value |= delay;
+ dev->reg.find_reg(REG_0x03).value |= delay;
}
else
{
- r->value |= 0x0f;
+ dev->reg.find_reg(REG_0x03).value |= 0x0f;
}
}
@@ -1031,8 +914,7 @@ void CommandSetGl124::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens
// set up GPIO for scan
gl124_setup_scan_gpio(dev,dev->settings.yres);
- // clear scan and feed count
- dev->interface->write_register(REG_0x0D, REG_0x0D_CLRLNCNT | REG_0x0D_CLRMCNT);
+ scanner_clear_scan_and_feed_counts(*dev);
// enable scan and motor
uint8_t val = dev->interface->read_register(REG_0x01);
@@ -1069,177 +951,43 @@ void CommandSetGl124::move_back_home(Genesys_Device* dev, bool wait_until_home)
scanner_move_back_home(*dev, wait_until_home);
}
-// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi
-// from very top of scanner
-void CommandSetGl124::search_start_position(Genesys_Device* dev) const
-{
- DBG_HELPER(dbg);
- int size;
- Genesys_Register_Set local_reg = dev->reg;
-
- int pixels = 600;
- int dpi = 300;
-
- /* sets for a 200 lines * 600 pixels */
- /* normal scan with no shading */
-
- // FIXME: the current approach of doing search only for one resolution does not work on scanners
- // whith employ different sensors with potentially different settings.
- const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, ScanMethod::FLATBED);
-
- ScanSession session;
- session.params.xres = dpi;
- session.params.yres = dpi;
- session.params.startx = 0;
- session.params.starty = 0; /*we should give a small offset here~60 steps */
- session.params.pixels = 600;
- session.params.lines = dev->model->search_lines;
- session.params.depth = 8;
- session.params.channels = 1;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::GRAY;
- session.params.color_filter = ColorFilter::GREEN;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::IGNORE_LINE_DISTANCE |
- ScanFlag::DISABLE_BUFFER_FULL_MOVE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &local_reg, session);
-
- // send to scanner
- dev->interface->write_registers(local_reg);
-
- size = pixels * dev->model->search_lines;
-
- std::vector<uint8_t> data(size);
-
- begin_scan(dev, sensor, &local_reg, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("search_start_position");
- end_scan(dev, &local_reg, true);
- dev->reg = local_reg;
- return;
- }
-
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- sanei_genesys_read_data_from_scanner(dev, data.data(), size);
-
- if (DBG_LEVEL >= DBG_data) {
- sanei_genesys_write_pnm_file("gl124_search_position.pnm", data.data(), 8, 1, pixels,
- dev->model->search_lines);
- }
-
- end_scan(dev, &local_reg, true);
-
- /* update regs to copy ASIC internal state */
- dev->reg = local_reg;
-
- for (auto& sensor_update :
- sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method))
- {
- sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels,
- dev->model->search_lines);
- }
-}
-
-// sets up register for coarse gain calibration
-// todo: check it for scanners using it
-void CommandSetGl124::init_regs_for_coarse_calibration(Genesys_Device* dev,
- const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs) const
-{
- DBG_HELPER(dbg);
-
- ScanSession session;
- session.params.xres = dev->settings.xres;
- session.params.yres = dev->settings.yres;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel();
- session.params.lines = 20;
- session.params.depth = 16;
- session.params.channels = dev->settings.get_channels();
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = dev->settings.scan_mode;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::FEEDING |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &regs, session);
-
- sanei_genesys_set_motor_power(regs, false);
-
- DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__,
- sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres);
-
- dev->interface->write_registers(regs);
-}
-
-
// init registers for shading calibration shading calibration is done at dpihw
void CommandSetGl124::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
- int move, resolution, dpihw, factor;
-
- /* initial calibration reg values */
- regs = dev->reg;
-
- dev->calib_channels = 3;
- dev->calib_lines = dev->model->shading_lines;
- dpihw = sensor.get_register_hwdpi(dev->settings.xres);
- if(dpihw>=2400)
- {
- dev->calib_lines *= 2;
- }
- resolution=dpihw;
- unsigned ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres);
+ unsigned channels = 3;
+ unsigned resolution = sensor.shading_resolution;
- resolution /= ccd_size_divisor;
- dev->calib_lines /= ccd_size_divisor; // reducing just because we reduced the resolution
+ unsigned calib_lines =
+ static_cast<unsigned>(dev->model->y_size_calib_mm * resolution / MM_PER_INCH);
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution,
- dev->calib_channels,
+ const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
- dev->calib_resolution = resolution;
- dev->calib_total_bytes_to_read = 0;
- factor = calib_sensor.optical_res / resolution;
- dev->calib_pixels = calib_sensor.sensor_pixels / factor;
/* distance to move to reach white target at high resolution */
- move=0;
+ unsigned move=0;
if (dev->settings.yres >= 1200) {
move = static_cast<int>(dev->model->y_offset_calib_white);
move = static_cast<int>((move * (dev->motor.base_ydpi/4)) / MM_PER_INCH);
}
- DBG (DBG_io, "%s: move=%d steps\n", __func__, move);
ScanSession session;
session.params.xres = resolution;
session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = move;
- session.params.pixels = dev->calib_pixels;
- session.params.lines = dev->calib_lines;
+ session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
+ session.params.lines = calib_lines;
session.params.depth = 16;
- session.params.channels = dev->calib_channels;
+ session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = ColorFilter::RED;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
- ScanFlag::DISABLE_BUFFER_FULL_MOVE |
- ScanFlag::IGNORE_LINE_DISTANCE;
+ ScanFlag::DISABLE_BUFFER_FULL_MOVE;
compute_session(dev, session, calib_sensor);
try {
@@ -1250,7 +998,7 @@ void CommandSetGl124::init_regs_for_shading(Genesys_Device* dev, const Genesys_S
}
sanei_genesys_set_motor_power(regs, false);
- dev->interface->write_registers(regs);
+ dev->calib_session = session;
}
void CommandSetGl124::wait_for_motor_stop(Genesys_Device* dev) const
@@ -1272,56 +1020,6 @@ void CommandSetGl124::wait_for_motor_stop(Genesys_Device* dev) const
dev->interface->sleep_ms(50);
}
-/** @brief set up registers for the actual scan
- */
-void CommandSetGl124::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const
-{
- DBG_HELPER(dbg);
- float move;
- int move_dpi;
- float start;
-
- debug_dump(DBG_info, dev->settings);
-
- /* y (motor) distance to move to reach scanned area */
- move_dpi = dev->motor.base_ydpi/4;
- move = static_cast<float>(dev->model->y_offset);
- move += static_cast<float>(dev->settings.tl_y);
- move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
- DBG (DBG_info, "%s: move=%f steps\n", __func__, move);
-
- if (dev->settings.get_channels() * dev->settings.yres >= 600 && move > 700) {
- scanner_move(*dev, dev->model->default_method, static_cast<unsigned>(move - 500),
- Direction::FORWARD);
- move=500;
- }
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
-
- /* start */
- start = static_cast<float>(dev->model->x_offset);
- start += static_cast<float>(dev->settings.tl_x);
- start /= sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres);
- start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
-
- ScanSession session;
- session.params.xres = dev->settings.xres;
- session.params.yres = dev->settings.yres;
- session.params.startx = static_cast<unsigned>(start);
- session.params.starty = static_cast<unsigned>(move);
- session.params.pixels = dev->settings.pixels;
- session.params.requested_pixels = dev->settings.requested_pixels;
- session.params.lines = dev->settings.lines;
- session.params.depth = dev->settings.depth;
- session.params.channels = dev->settings.get_channels();
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = dev->settings.scan_mode;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::NONE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &dev->reg, session);
-}
-
/**
* Send shading calibration data. The buffer is considered to always hold values
* for all the channels.
@@ -1330,8 +1028,7 @@ void CommandSetGl124::send_shading_data(Genesys_Device* dev, const Genesys_Senso
std::uint8_t* data, int size) const
{
DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size);
- uint32_t addr, length, x, factor, segcnt, pixels, i;
- uint16_t dpiset,dpihw;
+ std::uint32_t addr, length, segcnt, pixels, i;
uint8_t *ptr, *src;
/* logical size of a color as seen by generic code of the frontend */
@@ -1339,16 +1036,6 @@ void CommandSetGl124::send_shading_data(Genesys_Device* dev, const Genesys_Senso
std::uint32_t strpixel = dev->session.pixel_startx;
std::uint32_t endpixel = dev->session.pixel_endx;
segcnt = dev->reg.get24(REG_SEGCNT);
- if(endpixel==0)
- {
- endpixel=segcnt;
- }
-
- /* compute deletion factor */
- dpiset = dev->reg.get16(REG_DPISET);
- dpihw = sensor.get_register_hwdpi(dpiset);
- factor=dpihw/dpiset;
- DBG( DBG_io2, "%s: factor=%d\n",__func__,factor);
/* turn pixel value into bytes 2x16 bits words */
strpixel*=2*2; /* 2 words of 2 bytes */
@@ -1359,7 +1046,7 @@ void CommandSetGl124::send_shading_data(Genesys_Device* dev, const Genesys_Senso
dev->interface->record_key_value("shading_start_pixel", std::to_string(strpixel));
dev->interface->record_key_value("shading_pixels", std::to_string(pixels));
dev->interface->record_key_value("shading_length", std::to_string(length));
- dev->interface->record_key_value("shading_factor", std::to_string(factor));
+ dev->interface->record_key_value("shading_factor", std::to_string(sensor.shading_factor));
dev->interface->record_key_value("shading_segcnt", std::to_string(segcnt));
dev->interface->record_key_value("shading_segment_count",
std::to_string(dev->session.segment_count));
@@ -1375,47 +1062,18 @@ void CommandSetGl124::send_shading_data(Genesys_Device* dev, const Genesys_Senso
ptr = buffer.data();
/* iterate on both sensor segment */
- for(x=0;x<pixels;x+=4*factor)
- {
+ for (unsigned x = 0; x < pixels; x += 4 * sensor.shading_factor) {
/* coefficient source */
src=data+x+strpixel+i*length;
/* iterate over all the segments */
- switch (dev->session.segment_count) {
- case 1:
- ptr[0+pixels*0]=src[0+segcnt*0];
- ptr[1+pixels*0]=src[1+segcnt*0];
- ptr[2+pixels*0]=src[2+segcnt*0];
- ptr[3+pixels*0]=src[3+segcnt*0];
- break;
- case 2:
- ptr[0+pixels*0]=src[0+segcnt*0];
- ptr[1+pixels*0]=src[1+segcnt*0];
- ptr[2+pixels*0]=src[2+segcnt*0];
- ptr[3+pixels*0]=src[3+segcnt*0];
- ptr[0+pixels*1]=src[0+segcnt*1];
- ptr[1+pixels*1]=src[1+segcnt*1];
- ptr[2+pixels*1]=src[2+segcnt*1];
- ptr[3+pixels*1]=src[3+segcnt*1];
- break;
- case 4:
- ptr[0+pixels*0]=src[0+segcnt*0];
- ptr[1+pixels*0]=src[1+segcnt*0];
- ptr[2+pixels*0]=src[2+segcnt*0];
- ptr[3+pixels*0]=src[3+segcnt*0];
- ptr[0+pixels*1]=src[0+segcnt*2];
- ptr[1+pixels*1]=src[1+segcnt*2];
- ptr[2+pixels*1]=src[2+segcnt*2];
- ptr[3+pixels*1]=src[3+segcnt*2];
- ptr[0+pixels*2]=src[0+segcnt*1];
- ptr[1+pixels*2]=src[1+segcnt*1];
- ptr[2+pixels*2]=src[2+segcnt*1];
- ptr[3+pixels*2]=src[3+segcnt*1];
- ptr[0+pixels*3]=src[0+segcnt*3];
- ptr[1+pixels*3]=src[1+segcnt*3];
- ptr[2+pixels*3]=src[2+segcnt*3];
- ptr[3+pixels*3]=src[3+segcnt*3];
- break;
+ for (unsigned s = 0; s < dev->session.segment_count; s++)
+ {
+ unsigned segnum = dev->session.segment_count > 1 ? sensor.segment_order[s] : 0;
+ ptr[0+pixels*s]=src[0+segcnt*segnum];
+ ptr[1+pixels*s]=src[1+segcnt*segnum];
+ ptr[2+pixels*s]=src[2+segcnt*segnum];
+ ptr[3+pixels*s]=src[3+segcnt*segnum];
}
/* next shading coefficient */
@@ -1433,20 +1091,17 @@ void CommandSetGl124::send_shading_data(Genesys_Device* dev, const Genesys_Senso
* by doing a 600 dpi scan
* @param dev scanner device
*/
-static void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs)
+void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs)
{
(void) sensor;
DBG_HELPER(dbg);
- int pixels;
- int size;
unsigned resolution = 600;
unsigned channels = 3;
const auto& move_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
- pixels = (move_sensor.sensor_pixels * 600) / move_sensor.optical_res;
/* initial calibration reg values */
regs = dev->reg;
@@ -1456,7 +1111,7 @@ static void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor&
session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = 0;
- session.params.pixels = pixels;
+ session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
session.params.lines = 1;
session.params.depth = 8;
session.params.channels = channels;
@@ -1466,14 +1121,12 @@ static void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor&
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, move_sensor);
dev->cmd_set->init_regs_for_scan_session(dev, move_sensor, &regs, session);
- size = pixels * 3;
- std::vector<uint8_t> line(size);
-
// write registers and scan data
dev->interface->write_registers(regs);
@@ -1486,14 +1139,13 @@ static void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor&
return;
}
- sanei_genesys_read_data_from_scanner(dev, line.data(), size);
+ auto image = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
// stop scanning
scanner_stop_action(*dev);
- if (DBG_LEVEL >= DBG_data)
- {
- sanei_genesys_write_pnm_file("gl124_movetocalarea.pnm", line.data(), 8, 3, pixels, 1);
+ if (dbg_log_image_data()) {
+ write_tiff_file("gl124_movetocalarea.tiff", image);
}
}
@@ -1505,513 +1157,60 @@ static void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor&
SensorExposure CommandSetGl124::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
- DBG_HELPER(dbg);
- int num_pixels;
- int total_size;
- int resolution;
- int dpihw;
- int i, j;
- int val;
- int channels;
- int avg[3];
- int turn;
- uint16_t exp[3],target;
-
- /* move to calibration area */
- move_to_calibration_area(dev, sensor, regs);
-
- /* offset calibration is always done in 16 bit depth color mode */
- channels = 3;
- dpihw = sensor.get_register_hwdpi(dev->settings.xres);
- resolution = dpihw;
- unsigned ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres);
- resolution /= ccd_size_divisor;
-
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
- dev->settings.scan_method);
- num_pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res;
-
- /* initial calibration reg values */
- regs = dev->reg;
-
- ScanSession session;
- session.params.xres = resolution;
- session.params.yres = resolution;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = num_pixels;
- session.params.lines = 1;
- session.params.depth = 16;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, calib_sensor);
-
- init_regs_for_scan_session(dev, calib_sensor, &regs, session);
-
- total_size = num_pixels * channels * (session.params.depth / 8) * 1;
- std::vector<uint8_t> line(total_size);
-
- // initial loop values and boundaries
- exp[0] = calib_sensor.exposure.red;
- exp[1] = calib_sensor.exposure.green;
- exp[2] = calib_sensor.exposure.blue;
- target=sensor.gain_white_ref*256;
-
- turn = 0;
-
- /* no move during led calibration */
- sanei_genesys_set_motor_power(regs, false);
- bool acceptable = false;
- do
- {
- // set up exposure
- regs.set24(REG_EXPR, exp[0]);
- regs.set24(REG_EXPG, exp[1]);
- regs.set24(REG_EXPB, exp[2]);
-
- // write registers and scan data
- dev->interface->write_registers(regs);
-
- DBG(DBG_info, "%s: starting line reading\n", __func__);
- begin_scan(dev, calib_sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("led_calibration");
- scanner_stop_action(*dev);
- return calib_sensor.exposure;
- }
-
- sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
-
- // stop scanning
- scanner_stop_action(*dev);
-
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[30];
- std::snprintf(fn, 30, "gl124_led_%02d.pnm", turn);
- sanei_genesys_write_pnm_file(fn, line.data(), session.params.depth, channels, num_pixels,
- 1);
- }
-
- /* compute average */
- for (j = 0; j < channels; j++)
- {
- avg[j] = 0;
- for (i = 0; i < num_pixels; i++)
- {
- if (dev->model->is_cis)
- val =
- line[i * 2 + j * 2 * num_pixels + 1] * 256 +
- line[i * 2 + j * 2 * num_pixels];
- else
- val =
- line[i * 2 * channels + 2 * j + 1] * 256 +
- line[i * 2 * channels + 2 * j];
- avg[j] += val;
- }
-
- avg[j] /= num_pixels;
- }
-
- DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]);
-
- /* check if exposure gives average within the boundaries */
- acceptable = true;
- for(i=0;i<3;i++)
- {
- /* we accept +- 2% delta from target */
- if(abs(avg[i]-target)>target/50)
- {
- float prev_weight = 0.5;
- exp[i] = exp[i] * prev_weight + ((exp[i] * target) / avg[i]) * (1 - prev_weight);
- acceptable = false;
- }
- }
-
- turn++;
- }
- while (!acceptable && turn < 100);
-
- DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]);
-
- // set these values as final ones for scan
- dev->reg.set24(REG_EXPR, exp[0]);
- dev->reg.set24(REG_EXPG, exp[1]);
- dev->reg.set24(REG_EXPB, exp[2]);
-
- return { exp[0], exp[1], exp[2] };
+ return scanner_led_calibration(*dev, sensor, regs);
}
-/**
- * average dark pixels of a 8 bits scan
- */
-static int
-dark_average (uint8_t * data, unsigned int pixels, unsigned int lines,
- unsigned int channels, unsigned int black)
-{
- unsigned int i, j, k, average, count;
- unsigned int avg[3];
- uint8_t val;
-
- /* computes average value on black margin */
- for (k = 0; k < channels; k++)
- {
- avg[k] = 0;
- count = 0;
- for (i = 0; i < lines; i++)
- {
- for (j = 0; j < black; j++)
- {
- val = data[i * channels * pixels + j + k];
- avg[k] += val;
- count++;
- }
- }
- if (count)
- avg[k] /= count;
- DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]);
- }
- average = 0;
- for (i = 0; i < channels; i++)
- average += avg[i];
- average /= channels;
- DBG(DBG_info, "%s: average = %d\n", __func__, average);
- return average;
-}
-
-
void CommandSetGl124::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
- DBG_HELPER(dbg);
- unsigned channels;
- int pass = 0, avg, total_size;
- int topavg, bottomavg, lines;
- int top, bottom, black_pixels, pixels;
-
- // no gain nor offset for TI AFE
- uint8_t reg0a = dev->interface->read_register(REG_0x0A);
- if (((reg0a & REG_0x0A_SIFSEL) >> REG_0x0AS_SIFSEL) == 3) {
- return;
- }
-
- /* offset calibration is always done in color mode */
- channels = 3;
- dev->calib_pixels = sensor.sensor_pixels;
- lines=1;
- pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
- black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res;
- DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
-
- ScanSession session;
- session.params.xres = sensor.optical_res;
- session.params.yres = sensor.optical_res;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = pixels;
- session.params.lines = lines;
- session.params.depth = 8;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &regs, session);
-
- sanei_genesys_set_motor_power(regs, false);
-
- /* allocate memory for scans */
- total_size = pixels * channels * lines * (session.params.depth / 8);
-
- std::vector<uint8_t> first_line(total_size);
- std::vector<uint8_t> second_line(total_size);
-
- /* init gain */
- dev->frontend.set_gain(0, 0);
- dev->frontend.set_gain(1, 0);
- dev->frontend.set_gain(2, 0);
-
- /* scan with no move */
- bottom = 10;
- dev->frontend.set_offset(0, bottom);
- dev->frontend.set_offset(1, bottom);
- dev->frontend.set_offset(2, bottom);
-
- set_fe(dev, sensor, AFE_SET);
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting first line reading\n", __func__);
- begin_scan(dev, sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("offset_calibration");
- return;
- }
-
- sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size);
- if (DBG_LEVEL >= DBG_data)
- {
- char title[30];
- std::snprintf(title, 30, "gl124_offset%03d.pnm", bottom);
- sanei_genesys_write_pnm_file(title, first_line.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels);
- DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg);
-
- /* now top value */
- top = 255;
- dev->frontend.set_offset(0, top);
- dev->frontend.set_offset(1, top);
- dev->frontend.set_offset(2, top);
- set_fe(dev, sensor, AFE_SET);
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting second line reading\n", __func__);
- begin_scan(dev, sensor, &regs, true);
- sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
-
- topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
- DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg);
-
- /* loop until acceptable level */
- while ((pass < 32) && (top - bottom > 1))
- {
- pass++;
-
- /* settings for new scan */
- dev->frontend.set_offset(0, (top + bottom) / 2);
- dev->frontend.set_offset(1, (top + bottom) / 2);
- dev->frontend.set_offset(2, (top + bottom) / 2);
-
- // scan with no move
- set_fe(dev, sensor, AFE_SET);
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting second line reading\n", __func__);
- begin_scan(dev, sensor, &regs, true);
- sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
-
- if (DBG_LEVEL >= DBG_data)
- {
- char title[30];
- std::snprintf(title, 30, "gl124_offset%03d.pnm", dev->frontend.get_offset(1));
- sanei_genesys_write_pnm_file(title, second_line.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
- DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1));
-
- /* compute new boundaries */
- if (topavg == avg)
- {
- topavg = avg;
- top = dev->frontend.get_offset(1);
- }
- else
- {
- bottomavg = avg;
- bottom = dev->frontend.get_offset(1);
- }
- }
- DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
- dev->frontend.get_offset(0),
- dev->frontend.get_offset(1),
- dev->frontend.get_offset(2));
+ scanner_offset_calibration(*dev, sensor, regs);
}
-
-/* alternative coarse gain calibration
- this on uses the settings from offset_calibration and
- uses only one scanline
- */
-/*
- with offset and coarse calibration we only want to get our input range into
- a reasonable shape. the fine calibration of the upper and lower bounds will
- be done with shading.
- */
void CommandSetGl124::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const
{
- DBG_HELPER_ARGS(dbg, "dpi = %d", dpi);
- int pixels;
- int total_size;
- int i, j, channels;
- int max[3];
- float gain[3],coeff;
- int val, code, lines;
-
- // no gain nor offset for TI AFE
- uint8_t reg0a = dev->interface->read_register(REG_0x0A);
- if (((reg0a & REG_0x0A_SIFSEL) >> REG_0x0AS_SIFSEL) == 3) {
- return;
- }
-
- /* coarse gain calibration is always done in color mode */
- channels = 3;
-
- if(dev->settings.xres<sensor.optical_res)
- {
- coeff = 0.9f;
- } else {
- coeff = 1.0f;
- }
- lines=10;
- pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
-
- ScanSession session;
- session.params.xres = sensor.optical_res;
- session.params.yres = sensor.optical_res;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = pixels;
- session.params.lines = lines;
- session.params.depth = 8;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- try {
- init_regs_for_scan_session(dev, sensor, &regs, session);
- } catch (...) {
- catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); });
- throw;
- }
-
- sanei_genesys_set_motor_power(regs, false);
-
- dev->interface->write_registers(regs);
-
- total_size = pixels * channels * (16 / session.params.depth) * lines;
-
- std::vector<uint8_t> line(total_size);
-
- set_fe(dev, sensor, AFE_SET);
- begin_scan(dev, sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("coarse_gain_calibration");
- scanner_stop_action(*dev);
- move_back_home(dev, true);
- return;
- }
-
- sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
-
- if (DBG_LEVEL >= DBG_data) {
- sanei_genesys_write_pnm_file("gl124_gain.pnm", line.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- /* average value on each channel */
- for (j = 0; j < channels; j++)
- {
- max[j] = 0;
- for (i = pixels/4; i < (pixels*3/4); i++)
- {
- if (dev->model->is_cis) {
- val = line[i + j * pixels];
- } else {
- val = line[i * channels + j];
- }
-
- max[j] += val;
- }
- max[j] = max[j] / (pixels/2);
-
- gain[j] = (static_cast<float>(sensor.gain_white_ref) * coeff) / max[j];
-
- /* turn logical gain value into gain code, checking for overflow */
- code = static_cast<int>(283 - 208 / gain[j]);
- if (code > 255)
- code = 255;
- else if (code < 0)
- code = 0;
- dev->frontend.set_gain(j, code);
-
- DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j],
- gain[j], dev->frontend.get_gain(j));
- }
-
- if (dev->model->is_cis) {
- uint8_t gain0 = dev->frontend.get_gain(0);
- if (gain0 > dev->frontend.get_gain(1)) {
- gain0 = dev->frontend.get_gain(1);
- }
- if (gain0 > dev->frontend.get_gain(2)) {
- gain0 = dev->frontend.get_gain(2);
- }
- dev->frontend.set_gain(0, gain0);
- dev->frontend.set_gain(1, gain0);
- dev->frontend.set_gain(2, gain0);
- }
-
- if (channels == 1) {
- dev->frontend.set_gain(0, dev->frontend.get_gain(1));
- dev->frontend.set_gain(2, dev->frontend.get_gain(1));
- }
-
- scanner_stop_action(*dev);
-
- move_back_home(dev, true);
+ scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
}
// wait for lamp warmup by scanning the same line until difference
// between 2 scans is below a threshold
void CommandSetGl124::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* reg, int* channels,
- int* total_size) const
+ Genesys_Register_Set* reg) const
{
DBG_HELPER(dbg);
- int num_pixels;
-
- *channels=3;
*reg = dev->reg;
+ auto flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA |
+ ScanFlag::SINGLE_LINE |
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ flags |= ScanFlag::USE_XPA;
+ }
+
ScanSession session;
- session.params.xres = sensor.optical_res;
+ session.params.xres = sensor.full_resolution;
session.params.yres = dev->motor.base_ydpi;
- session.params.startx = sensor.sensor_pixels / 4;
+ session.params.startx = dev->model->x_size_calib_mm * sensor.full_resolution / MM_PER_INCH / 4;
session.params.starty = 0;
- session.params.pixels = sensor.sensor_pixels / 2;
+ session.params.pixels = dev->model->x_size_calib_mm * sensor.full_resolution / MM_PER_INCH / 2;
session.params.lines = 1;
- session.params.depth = 8;
- session.params.channels = *channels;
+ session.params.depth = dev->model->bpp_color_values.front();
+ session.params.channels = 3;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
+ session.params.flags = flags;
+
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, reg, session);
- num_pixels = session.output_pixels;
-
- *total_size = num_pixels * 3 * 1; /* colors * bytes_per_color * scan lines */
-
sanei_genesys_set_motor_power(*reg, false);
- dev->interface->write_registers(*reg);
}
/** @brief default GPIO values
@@ -2049,64 +1248,8 @@ static void gl124_init_gpio(Genesys_Device* dev)
static void gl124_init_memory_layout(Genesys_Device* dev)
{
DBG_HELPER(dbg);
- int idx = 0;
- /* point to per model memory layout */
- if (dev->model->model_id == ModelId::CANON_LIDE_110 ||
- dev->model->model_id == ModelId::CANON_LIDE_120)
- {
- idx = 0;
- }
- else
- { /* canon LiDE 210 and 220 case */
- idx = 1;
- }
-
- /* setup base address for shading data. */
- /* values must be multiplied by 8192=0x4000 to give address on AHB */
- /* R-Channel shading bank0 address setting for CIS */
- dev->interface->write_register(0xd0, layouts[idx].rd0);
- /* G-Channel shading bank0 address setting for CIS */
- dev->interface->write_register(0xd1, layouts[idx].rd1);
- /* B-Channel shading bank0 address setting for CIS */
- dev->interface->write_register(0xd2, layouts[idx].rd2);
-
- /* setup base address for scanned data. */
- /* values must be multiplied by 1024*2=0x0800 to give address on AHB */
- /* R-Channel ODD image buffer 0x0124->0x92000 */
- /* size for each buffer is 0x16d*1k word */
- dev->interface->write_register(0xe0, layouts[idx].re0);
- dev->interface->write_register(0xe1, layouts[idx].re1);
- /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/
- dev->interface->write_register(0xe2, layouts[idx].re2);
- dev->interface->write_register(0xe3, layouts[idx].re3);
-
- /* R-Channel EVEN image buffer 0x0292 */
- dev->interface->write_register(0xe4, layouts[idx].re4);
- dev->interface->write_register(0xe5, layouts[idx].re5);
- /* R-Channel EVEN image buffer end-address 0x03ff*/
- dev->interface->write_register(0xe6, layouts[idx].re6);
- dev->interface->write_register(0xe7, layouts[idx].re7);
-
- /* same for green, since CIS, same addresses */
- dev->interface->write_register(0xe8, layouts[idx].re0);
- dev->interface->write_register(0xe9, layouts[idx].re1);
- dev->interface->write_register(0xea, layouts[idx].re2);
- dev->interface->write_register(0xeb, layouts[idx].re3);
- dev->interface->write_register(0xec, layouts[idx].re4);
- dev->interface->write_register(0xed, layouts[idx].re5);
- dev->interface->write_register(0xee, layouts[idx].re6);
- dev->interface->write_register(0xef, layouts[idx].re7);
-
-/* same for blue, since CIS, same addresses */
- dev->interface->write_register(0xf0, layouts[idx].re0);
- dev->interface->write_register(0xf1, layouts[idx].re1);
- dev->interface->write_register(0xf2, layouts[idx].re2);
- dev->interface->write_register(0xf3, layouts[idx].re3);
- dev->interface->write_register(0xf4, layouts[idx].re4);
- dev->interface->write_register(0xf5, layouts[idx].re5);
- dev->interface->write_register(0xf6, layouts[idx].re6);
- dev->interface->write_register(0xf7, layouts[idx].re7);
+ apply_reg_settings_to_device_write_only(*dev, dev->memory_layout.regs);
}
/**
@@ -2118,7 +1261,7 @@ void CommandSetGl124::init(Genesys_Device* dev) const
DBG_INIT ();
DBG_HELPER(dbg);
- sanei_genesys_asic_init(dev, 0);
+ sanei_genesys_asic_init(dev);
}
@@ -2244,26 +1387,5 @@ void CommandSetGl124::eject_document(Genesys_Device* dev) const
throw SaneException("not implemented");
}
-void CommandSetGl124::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
- bool forward, bool black) const
-{
- (void) dev;
- (void) sensor;
- (void) forward;
- (void) black;
- throw SaneException("not implemented");
-}
-
-void CommandSetGl124::move_to_ta(Genesys_Device* dev) const
-{
- (void) dev;
- throw SaneException("not implemented");
-}
-
-std::unique_ptr<CommandSet> create_gl124_cmd_set()
-{
- return std::unique_ptr<CommandSet>(new CommandSetGl124{});
-}
-
} // namespace gl124
} // namespace genesys
diff --git a/backend/genesys/gl124.h b/backend/genesys/gl124.h
index cdf8faf..ea7041e 100644
--- a/backend/genesys/gl124.h
+++ b/backend/genesys/gl124.h
@@ -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,17 +60,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs, int* channels,
- int* total_size) const override;
-
- 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_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@@ -148,8 +80,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;
@@ -165,8 +95,6 @@ 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;
@@ -175,11 +103,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,
int size) const override;
diff --git a/backend/genesys/gl646.cpp b/backend/genesys/gl646.cpp
index 04ee85e..61fa1e0 100644
--- a/backend/genesys/gl646.cpp
+++ b/backend/genesys/gl646.cpp
@@ -63,9 +63,336 @@ namespace {
constexpr unsigned CALIBRATION_LINES = 10;
} // namespace
-static void gl646_send_slope_table(Genesys_Device* dev, int table_nr,
- const std::vector<uint16_t>& slope_table,
- int steps);
+static void write_control(Genesys_Device* dev, const Genesys_Sensor& sensor, int resolution);
+
+
+static void gl646_set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set, int dpi);
+
+static void simple_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ const ScanSession& session, bool move,
+ 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);
+
+/**
+ * master motor settings table entry
+ */
+struct Motor_Master
+{
+ 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
+};
+
+/**
+ * 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 */
+};
/**
* reads value from gpio endpoint
@@ -105,44 +432,6 @@ static void gl646_stop_motor(Genesys_Device* dev)
}
/**
- * find the closest match in mode tables for the given resolution and scan mode.
- * @param sensor id of the sensor
- * @param required required resolution
- * @param color true is color mode
- * @return the closest resolution for the sensor and mode
- */
-static unsigned get_closest_resolution(SensorId sensor_id, int required, unsigned channels)
-{
- unsigned best_res = 0;
- unsigned best_diff = 9600;
-
- for (const auto& sensor : *s_sensors) {
- if (sensor_id != sensor.sensor_id)
- continue;
-
- // exit on perfect match
- if (sensor.resolutions.matches(required) && sensor.matches_channel_count(channels)) {
- DBG(DBG_info, "%s: match found for %d\n", __func__, required);
- return required;
- }
-
- // computes distance and keep mode if it is closer than previous
- if (sensor.matches_channel_count(channels)) {
- for (auto res : sensor.resolutions.resolutions()) {
- unsigned curr_diff = std::abs(static_cast<int>(res) - static_cast<int>(required));
- if (curr_diff < best_diff) {
- best_res = res;
- best_diff = curr_diff;
- }
- }
- }
- }
-
- DBG(DBG_info, "%s: closest match for %d is %d\n", __func__, required, best_res);
- return best_res;
-}
-
-/**
* Returns the cksel values used by the required scan mode.
* @param sensor id of the sensor
* @param required required resolution
@@ -157,7 +446,6 @@ static int get_cksel(SensorId sensor_id, int required, unsigned channels)
sensor.matches_channel_count(channels))
{
unsigned cksel = sensor.ccd_pixels_per_system_pixel();
- DBG(DBG_io, "%s: match found for %d (cksel=%d)\n", __func__, required, cksel);
return cksel;
}
}
@@ -177,7 +465,6 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
uint32_t move = session.params.starty;
- int i, nb;
Motor_Master *motor = nullptr;
uint32_t z1, z2;
int feedl;
@@ -185,57 +472,47 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
/* for the given resolution, search for master
* motor mode setting */
- i = 0;
- nb = sizeof (motor_master) / sizeof (Motor_Master);
- while (i < nb)
- {
- if (dev->model->motor_id == motor_master[i].motor_id
- && motor_master[i].dpi == session.params.yres
- && motor_master[i].channels == session.params.channels)
- {
- motor = &motor_master[i];
- }
- i++;
+ for (unsigned i = 0; i < sizeof (motor_master) / sizeof (Motor_Master); ++i) {
+ if (dev->model->motor_id == motor_master[i].motor_id &&
+ motor_master[i].dpi == session.params.yres &&
+ motor_master[i].channels == session.params.channels)
+ {
+ motor = &motor_master[i];
+ }
}
- if (motor == nullptr)
- {
+ if (motor == nullptr) {
throw SaneException("unable to find settings for motor %d at %d dpi, color=%d",
static_cast<unsigned>(dev->model->motor_id),
session.params.yres, session.params.channels);
}
- /* now we can search for the specific sensor settings */
- i = 0;
-
- // now apply values from settings to registers
- regs->set16(REG_EXPR, sensor.exposure.red);
- regs->set16(REG_EXPG, sensor.exposure.green);
- regs->set16(REG_EXPB, sensor.exposure.blue);
-
- for (const auto& reg : sensor.custom_regs) {
- regs->set8(reg.address, reg.value);
- }
+ scanner_setup_sensor(*dev, sensor, *regs);
/* now generate slope tables : we are not using generate_slope_table3 yet */
- auto slope_table1 = create_slope_table(motor->slope1, motor->slope1.max_speed_w, StepType::FULL,
- 1, 4, get_slope_table_max_size(AsicType::GL646));
- auto slope_table2 = create_slope_table(motor->slope2, motor->slope2.max_speed_w, StepType::FULL,
- 1, 4, get_slope_table_max_size(AsicType::GL646));
+ auto slope_table1 = create_slope_table_for_speed(motor->slope1, motor->slope1.max_speed_w,
+ StepType::FULL, 1, 4,
+ get_slope_table_max_size(AsicType::GL646));
+ auto slope_table2 = create_slope_table_for_speed(motor->slope2, motor->slope2.max_speed_w,
+ StepType::FULL, 1, 4,
+ get_slope_table_max_size(AsicType::GL646));
/* R01 */
/* now setup other registers for final scan (ie with shading enabled) */
/* watch dog + shading + scan enable */
- regs->find_reg(0x01).value |= REG_0x01_DOGENB | REG_0x01_DVDSET | REG_0x01_SCAN;
+ regs->find_reg(0x01).value |= REG_0x01_DOGENB | REG_0x01_SCAN;
if (dev->model->is_cis) {
regs->find_reg(0x01).value |= REG_0x01_CISSET;
} else {
regs->find_reg(0x01).value &= ~REG_0x01_CISSET;
}
- /* if device has no calibration, don't enable shading correction */
- if (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)
+ // if device has no calibration, don't enable shading correction
+ if (has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) ||
+ has_flag(session.params.flags, ScanFlag::DISABLE_SHADING))
{
regs->find_reg(0x01).value &= ~REG_0x01_DVDSET;
+ } else {
+ regs->find_reg(0x01).value |= REG_0x01_DVDSET;
}
regs->find_reg(0x01).value &= ~REG_0x01_FASTMOD;
@@ -284,7 +561,7 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
break;
}
- if (dev->model->is_sheetfed) {
+ if (dev->model->is_sheetfed || !has_flag(session.params.flags, ScanFlag::AUTO_GO_HOME)) {
regs->find_reg(0x02).value &= ~REG_0x02_AGOHOME;
} else {
regs->find_reg(0x02).value |= REG_0x02_AGOHOME;
@@ -314,14 +591,20 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
break;
}
- sanei_genesys_set_dpihw(*regs, sensor, sensor.optical_res);
+ sanei_genesys_set_dpihw(*regs, sensor.full_resolution);
/* gamma enable for scans */
- if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) {
+ if (has_flag(dev->model->flags, ModelFlag::GAMMA_14BIT)) {
regs->find_reg(0x05).value |= REG_0x05_GMM14BIT;
}
- regs->find_reg(0x05).value &= ~REG_0x05_GMMENB;
+ if (!has_flag(session.params.flags, ScanFlag::DISABLE_GAMMA) &&
+ session.params.depth < 16)
+ {
+ regs->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
+ } else {
+ regs->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB;
+ }
/* true CIS gray if needed */
if (dev->model->is_cis && session.params.channels == 1 && dev->settings.true_gray) {
@@ -356,17 +639,17 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
// the steps count must be different by at most 128, otherwise it's impossible to construct
// a proper backtracking curve. We're using slightly lower limit to allow at least a minimum
// distance between accelerations (forward_steps, backward_steps)
- if (slope_table1.steps_count > slope_table2.steps_count + 100) {
- slope_table2.steps_count += slope_table1.steps_count - 100;
+ if (slope_table1.table.size() > slope_table2.table.size() + 100) {
+ slope_table2.expand_table(slope_table1.table.size() - 100, 1);
}
- if (slope_table2.steps_count > slope_table1.steps_count + 100) {
- slope_table1.steps_count += slope_table2.steps_count - 100;
+ if (slope_table2.table.size() > slope_table1.table.size() + 100) {
+ slope_table1.expand_table(slope_table2.table.size() - 100, 1);
}
- if (slope_table1.steps_count >= slope_table2.steps_count) {
- backward_steps += (slope_table1.steps_count - slope_table2.steps_count) * 2;
+ if (slope_table1.table.size() >= slope_table2.table.size()) {
+ backward_steps += (slope_table1.table.size() - slope_table2.table.size()) * 2;
} else {
- forward_steps += (slope_table2.steps_count - slope_table1.steps_count) * 2;
+ forward_steps += (slope_table2.table.size() - slope_table1.table.size()) * 2;
}
if (forward_steps > 255) {
@@ -382,8 +665,8 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
forward_steps -= backward_steps - 255;
}
- regs->find_reg(0x21).value = slope_table1.steps_count;
- regs->find_reg(0x24).value = slope_table2.steps_count;
+ regs->find_reg(0x21).value = slope_table1.table.size();
+ regs->find_reg(0x24).value = slope_table2.table.size();
regs->find_reg(0x22).value = forward_steps;
regs->find_reg(0x23).value = backward_steps;
@@ -401,8 +684,11 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
regs->set24(REG_MAXWD, session.output_line_bytes);
- regs->set16(REG_DPISET, session.output_resolution * session.ccd_size_divisor *
- sensor.ccd_pixels_per_system_pixel());
+ // FIXME: the incoming sensor is selected for incorrect resolution
+ const auto& dpiset_sensor = sanei_genesys_find_sensor(dev, session.params.xres,
+ session.params.channels,
+ session.params.scan_method);
+ regs->set16(REG_DPISET, dpiset_sensor.register_dpiset);
regs->set16(REG_LPERIOD, sensor.exposure_lperiod);
/* move distance must be adjusted to take into account the extra lines
@@ -410,8 +696,8 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
feedl = move;
if (session.num_staggered_lines + session.max_color_shift_lines > 0 && feedl != 0) {
- int feed_offset = ((session.max_color_shift_lines + session.num_staggered_lines) * dev->motor.optical_ydpi) /
- motor->dpi;
+ unsigned total_lines = session.max_color_shift_lines + session.num_staggered_lines;
+ int feed_offset = (total_lines * dev->motor.base_ydpi) / motor->dpi;
if (feedl > feed_offset) {
feedl = feedl - feed_offset;
}
@@ -424,8 +710,6 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
/* but head has moved due to shading calibration => dev->scanhead_position_primary */
if (feedl > 0)
{
- DBG(DBG_info, "%s: initial move=%d\n", __func__, feedl);
-
/* TODO clean up this when I'll fully understand.
* for now, special casing each motor */
switch (dev->model->motor_id) {
@@ -505,12 +789,12 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
if (motor->fastfed)
{
- feedl = feedl - 2 * slope_table2.steps_count -
- (slope_table1.steps_count >> step_shift);
+ feedl = feedl - 2 * slope_table2.table.size() -
+ (slope_table1.table.size() >> step_shift);
}
else
{
- feedl = feedl - (slope_table1.steps_count >> step_shift);
+ feedl = feedl - (slope_table1.table.size() >> step_shift);
}
break;
}
@@ -520,7 +804,6 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
feedl = 0;
}
- DBG(DBG_info, "%s: final move=%d\n", __func__, feedl);
regs->set24(REG_FEEDL, feedl);
regs->find_reg(0x65).value = motor->mtrpwm;
@@ -528,7 +811,7 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
sanei_genesys_calculate_zmod(regs->find_reg(0x02).value & REG_0x02_FASTFED,
sensor.exposure_lperiod,
slope_table1.table,
- slope_table1.steps_count,
+ slope_table1.table.size(),
move, motor->fwdbwd, &z1, &z2);
/* no z1/z2 for sheetfed scanners */
@@ -538,7 +821,7 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
}
regs->set16(REG_Z1MOD, z1);
regs->set16(REG_Z2MOD, z2);
- regs->find_reg(0x6b).value = slope_table2.steps_count;
+ regs->find_reg(0x6b).value = slope_table2.table.size();
regs->find_reg(0x6c).value =
(regs->find_reg(0x6c).value & REG_0x6C_TGTIME) | ((z1 >> 13) & 0x38) | ((z2 >> 16)
& 0x07);
@@ -548,10 +831,7 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
// setup analog frontend
gl646_set_fe(dev, sensor, AFE_SET, session.output_resolution);
- dev->read_buffer.clear();
- dev->read_buffer.alloc(session.buffer_size_read);
-
- build_image_pipeline(dev, session);
+ setup_image_pipeline(*dev, session);
dev->read_active = true;
@@ -578,32 +858,8 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
}
}
- gl646_send_slope_table(dev, 0, slope_table1.table, regs->get8(0x21));
- gl646_send_slope_table(dev, 1, slope_table2.table, regs->get8(0x6b));
-}
-
-
-/** copy sensor specific settings */
-/* *dev : device infos
- *regs : regiters to be set
- extended : do extended set up
- ccd_size_divisor: set up for half ccd resolution
- all registers 08-0B, 10-1D, 52-5E are set up. They shouldn't
- appear anywhere else but in register init
-*/
-static void
-gl646_setup_sensor (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * regs)
-{
- (void) dev;
- DBG(DBG_proc, "%s: start\n", __func__);
-
- for (const auto& reg_setting : sensor.custom_base_regs) {
- regs->set8(reg_setting.address, reg_setting.value);
- }
- // FIXME: all other drivers don't set exposure here
- regs_set_exposure(AsicType::GL646, *regs, sensor.exposure);
-
- DBG(DBG_proc, "%s: end\n", __func__);
+ scanner_send_slope_table(dev, sensor, 0, slope_table1.table);
+ scanner_send_slope_table(dev, sensor, 1, slope_table2.table);
}
/**
@@ -632,8 +888,8 @@ gl646_init_regs (Genesys_Device * dev)
for (addr = 0x60; addr <= 0x6d; addr++)
dev->reg.init_reg(addr, 0);
- dev->reg.find_reg(0x01).value = 0x20 /*0x22 */ ; /* enable shading, CCD, color, 1M */
- dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */
+ dev->reg.find_reg(0x01).value = 0x20 /*0x22 */ ; /* enable shading, CCD, color, 1M */
+ dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */
if (dev->model->motor_id == MotorId::MD_5345) {
dev->reg.find_reg(0x02).value |= 0x01; // half-step
}
@@ -648,8 +904,8 @@ gl646_init_regs (Genesys_Device * dev)
default:
break;
}
- dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */
- dev->reg.find_reg(0x04).value = 0x13 /*0x03 */ ; /* 8 bits data, 16 bits A/D, color, Wolfson fe *//* todo: according to spec, 0x0 is reserved? */
+ dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */
+ dev->reg.find_reg(0x04).value = 0x13 /*0x03 */ ; /* 8 bits data, 16 bits A/D, color, Wolfson fe *//* todo: according to spec, 0x0 is reserved? */
switch (dev->model->adc_id)
{
case AdcId::AD_XP200:
@@ -664,9 +920,9 @@ gl646_init_regs (Genesys_Device * dev)
const auto& sensor = sanei_genesys_find_sensor_any(dev);
dev->reg.find_reg(0x05).value = 0x00; /* 12 bits gamma, disable gamma, 24 clocks/pixel */
- sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res);
+ sanei_genesys_set_dpihw(dev->reg, sensor.full_resolution);
- if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) {
+ if (has_flag(dev->model->flags, ModelFlag::GAMMA_14BIT)) {
dev->reg.find_reg(0x05).value |= REG_0x05_GMM14BIT;
}
if (dev->model->adc_id == AdcId::AD_XP200) {
@@ -679,8 +935,7 @@ gl646_init_regs (Genesys_Device * dev)
dev->reg.find_reg(0x06).value = 0x18; // PWRBIT on, shading gain=8, normal AFE image capture
}
-
- gl646_setup_sensor(dev, sensor, &dev->reg);
+ scanner_setup_sensor(*dev, sensor, dev->reg);
dev->reg.find_reg(0x1e).value = 0xf0; /* watch-dog time */
@@ -788,54 +1043,15 @@ gl646_init_regs (Genesys_Device * dev)
dev->reg.find_reg(0x6c).value = 0x00; /* peroid times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE (one period time) */
}
-
-// Send slope table for motor movement slope_table in machine byte order
-static void gl646_send_slope_table(Genesys_Device* dev, int table_nr,
- const std::vector<uint16_t>& slope_table,
- int steps)
-{
- DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d)=%d .. %d", table_nr, steps, slope_table[0],
- slope_table[steps - 1]);
- int dpihw;
- int start_address;
-
- dpihw = dev->reg.find_reg(0x05).value >> 6;
-
- if (dpihw == 0) /* 600 dpi */
- start_address = 0x08000;
- else if (dpihw == 1) /* 1200 dpi */
- start_address = 0x10000;
- else if (dpihw == 2) /* 2400 dpi */
- start_address = 0x1f800;
- else {
- throw SaneException("Unexpected dpihw");
- }
-
- std::vector<uint8_t> table(steps * 2);
- for (int i = 0; i < steps; i++)
- {
- table[i * 2] = slope_table[i] & 0xff;
- table[i * 2 + 1] = slope_table[i] >> 8;
- }
-
- if (dev->interface->is_mock()) {
- dev->interface->record_slope_table(table_nr, slope_table);
- }
- dev->interface->write_buffer(0x3c, start_address + table_nr * 0x100, table.data(), steps * 2);
-}
-
// Set values of Analog Device type frontend
static void gl646_set_ad_fe(Genesys_Device* dev, uint8_t set)
{
DBG_HELPER(dbg);
int i;
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s(): setting DAC %u\n", __func__,
- static_cast<unsigned>(dev->model->adc_id));
+ if (set == AFE_INIT) {
- dev->frontend = dev->frontend_initial;
+ dev->frontend = dev->frontend_initial;
// write them to analog frontend
dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
@@ -888,8 +1104,7 @@ static void gl646_wm_hp3670(Genesys_Device* dev, const Genesys_Sensor& sensor, u
default: /* AFE_SET */
/* mode setup */
i = dev->frontend.regs.get_value(0x03);
- if (dpi > sensor.optical_res / 2)
- {
+ if (dpi > sensor.full_resolution / 2) {
/* fe_reg_0x03 must be 0x12 for 1200 dpi in WOLFSON_HP3670.
* WOLFSON_HP2400 in 1200 dpi mode works well with
* fe_reg_0x03 set to 0x32 or 0x12 but not to 0x02 */
@@ -947,11 +1162,8 @@ static void gl646_set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint
}
/* initialize analog frontend */
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s(): setting DAC %u\n", __func__,
- static_cast<unsigned>(dev->model->adc_id));
- dev->frontend = dev->frontend_initial;
+ if (set == AFE_INIT) {
+ dev->frontend = dev->frontend_initial;
// reset only done on init
dev->interface->write_fe_register(0x04, 0x80);
@@ -1174,14 +1386,15 @@ void CommandSetGl646::load_document(Genesys_Device* dev) const
regs.init_reg(0x24, 4);
/* generate slope table 2 */
- auto slope_table = create_slope_table(MotorSlope::create_from_steps(6000, 2400, 50), 2400,
- StepType::FULL, 1, 4,
- get_slope_table_max_size(AsicType::GL646));
+ auto slope_table = create_slope_table_for_speed(MotorSlope::create_from_steps(6000, 2400, 50),
+ 2400, StepType::FULL, 1, 4,
+ get_slope_table_max_size(AsicType::GL646));
// document loading:
// send regs
// start motor
// wait e1 status to become e0
- gl646_send_slope_table(dev, 1, slope_table.table, slope_table.steps_count);
+ const auto& sensor = sanei_genesys_find_sensor_any(dev);
+ scanner_send_slope_table(dev, sensor, 1, slope_table.table);
dev->interface->write_registers(regs);
@@ -1292,9 +1505,8 @@ void CommandSetGl646::eject_document(Genesys_Device* dev) const
// home sensor is set when document is inserted
if (status.is_at_home) {
dev->document = false;
- DBG(DBG_info, "%s: no more document to eject\n", __func__);
- DBG(DBG_proc, "%s: end\n", __func__);
- return;
+ DBG(DBG_info, "%s: no more document to eject\n", __func__);
+ return;
}
// there is a document inserted, eject it
@@ -1331,14 +1543,16 @@ void CommandSetGl646::eject_document(Genesys_Device* dev) const
regs.init_reg(0x24, 4);
/* generate slope table 2 */
- auto slope_table = create_slope_table(MotorSlope::create_from_steps(10000, 1600, 60), 1600,
- StepType::FULL, 1, 4,
- get_slope_table_max_size(AsicType::GL646));
+ auto slope_table = create_slope_table_for_speed(MotorSlope::create_from_steps(10000, 1600, 60),
+ 1600, StepType::FULL, 1, 4,
+ get_slope_table_max_size(AsicType::GL646));
// document eject:
// send regs
// start motor
// wait c1 status to become c8 : HOMESNR and ~MOTFLAG
- gl646_send_slope_table(dev, 1, slope_table.table, slope_table.steps_count);
+ // FIXME: sensor is not used.
+ const auto& sensor = sanei_genesys_find_sensor_any(dev);
+ scanner_send_slope_table(dev, sensor, 1, slope_table.table);
dev->interface->write_registers(regs);
@@ -1473,7 +1687,7 @@ void CommandSetGl646::move_back_home(Genesys_Device* dev, bool wait_until_home)
if (!i) /* the loop counted down to 0, scanner still is busy */
{
- dev->set_head_pos_unknown();
+ dev->set_head_pos_unknown(ScanHeadId::PRIMARY | ScanHeadId::SECONDARY);
throw SaneException(SANE_STATUS_DEVICE_BUSY, "motor is still on: device busy");
}
@@ -1489,15 +1703,15 @@ void CommandSetGl646::move_back_home(Genesys_Device* dev, bool wait_until_home)
session.params.startx = 0;
session.params.starty = 65535;
session.params.pixels = 600;
- session.params.requested_pixels = 600;
session.params.lines = 1;
session.params.depth = 8;
session.params.channels = 3;
session.params.scan_method = dev->model->default_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = ColorFilter::RED;
- session.params.flags = ScanFlag::USE_XCORRECTION |
- ScanFlag::REVERSE;
+ session.params.flags = ScanFlag::REVERSE |
+ ScanFlag::AUTO_GO_HOME |
+ ScanFlag::DISABLE_GAMMA;
if (dev->model->default_method == ScanMethod::TRANSPARENCY) {
session.params.flags |= ScanFlag::USE_XPA;
}
@@ -1520,8 +1734,7 @@ void CommandSetGl646::move_back_home(Genesys_Device* dev, bool wait_until_home)
/* registers are restored to an iddl state, give up if no head to park */
if (dev->model->is_sheetfed) {
- DBG(DBG_proc, "%s: end \n", __func__);
- return;
+ return;
}
// starts scan
@@ -1554,7 +1767,6 @@ void CommandSetGl646::move_back_home(Genesys_Device* dev, bool wait_until_home)
if (status.is_at_home) {
DBG(DBG_info, "%s: reached home position\n", __func__);
- DBG(DBG_proc, "%s: end\n", __func__);
dev->interface->sleep_ms(500);
dev->set_head_pos_zero(ScanHeadId::PRIMARY);
return;
@@ -1567,7 +1779,7 @@ void CommandSetGl646::move_back_home(Genesys_Device* dev, bool wait_until_home)
// stop the motor
catch_all_exceptions(__func__, [&](){ gl646_stop_motor (dev); });
catch_all_exceptions(__func__, [&](){ end_scan_impl(dev, &dev->reg, true, false); });
- dev->set_head_pos_unknown();
+ dev->set_head_pos_unknown(ScanHeadId::PRIMARY | ScanHeadId::SECONDARY);
throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home");
}
@@ -1576,165 +1788,60 @@ void CommandSetGl646::move_back_home(Genesys_Device* dev, bool wait_until_home)
}
/**
- * Automatically set top-left edge of the scan area by scanning an
- * area at 300 dpi from very top of scanner
- * @param dev device stucture describing the scanner
- */
-void CommandSetGl646::search_start_position(Genesys_Device* dev) const
-{
- DBG_HELPER(dbg);
- Genesys_Settings settings;
- unsigned int resolution, x, y;
-
- /* we scan at 300 dpi */
- resolution = get_closest_resolution(dev->model->sensor_id, 300, 1);
-
- // FIXME: the current approach of doing search only for one resolution does not work on scanners
- // whith employ different sensors with potentially different settings.
- const auto& sensor = sanei_genesys_find_sensor(dev, resolution, 1,
- dev->model->default_method);
-
- /* fill settings for a gray level scan */
- settings.scan_method = dev->model->default_method;
- settings.scan_mode = ScanColorMode::GRAY;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels = 600;
- settings.requested_pixels = settings.pixels;
- settings.lines = dev->model->search_lines;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
-
- // scan the desired area
- std::vector<uint8_t> data;
- simple_scan(dev, sensor, settings, true, true, false, data, "search_start_position");
-
- // handle stagger case : reorder gray data and thus loose some lines
- auto staggered_lines = dev->session.num_staggered_lines;
- if (staggered_lines > 0) {
- DBG(DBG_proc, "%s: 'un-staggering'\n", __func__);
- for (y = 0; y < settings.lines - staggered_lines; y++) {
- /* one point out of 2 is 'unaligned' */
- for (x = 0; x < settings.pixels; x += 2)
- {
- data[y * settings.pixels + x] = data[(y + staggered_lines) * settings.pixels + x];
- }
- }
- /* correct line number */
- settings.lines -= staggered_lines;
- }
-
- if (DBG_LEVEL >= DBG_data)
- {
- sanei_genesys_write_pnm_file("gl646_search_position.pnm", data.data(), settings.depth, 1,
- settings.pixels, settings.lines);
- }
-
- // now search reference points on the data
- for (auto& sensor_update :
- sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method))
- {
- sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0,
- resolution, settings.pixels, settings.lines);
- }
-}
-
-/**
- * internally overriden during effective calibration
- * sets up register for coarse gain calibration
- */
-void CommandSetGl646::init_regs_for_coarse_calibration(Genesys_Device* dev,
- const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs) const
-{
- DBG_HELPER(dbg);
- (void) dev;
- (void) sensor;
- (void) regs;
-}
-
-
-/**
* init registers for shading calibration
* we assume that scanner's head is on an area suiting shading calibration.
* We scan a full scan width area by the shading line number for the device
- * at either at full sensor's resolution or half depending upon ccd_size_divisor
- * @param dev scanner's device
*/
void CommandSetGl646::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
(void) regs;
- Genesys_Settings settings;
- int cksel = 1;
/* fill settings for scan : always a color scan */
int channels = 3;
+ unsigned cksel = get_cksel(dev->model->sensor_id, dev->settings.xres, channels);
+
+ unsigned resolution = sensor.get_optical_resolution() / cksel;
+ // FIXME: we select wrong calibration sensor
const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->settings.xres, channels,
dev->settings.scan_method);
- unsigned ccd_size_divisor = calib_sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres);
+ auto pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
- settings.scan_method = dev->settings.scan_method;
- settings.scan_mode = dev->settings.scan_mode;
- if (!dev->model->is_cis) {
- // FIXME: always a color scan, but why don't we set scan_mode to COLOR_SINGLE_PASS always?
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- }
- settings.xres = sensor.optical_res / ccd_size_divisor;
- cksel = get_cksel(dev->model->sensor_id, dev->settings.xres, channels);
- settings.xres = settings.xres / cksel;
- settings.yres = settings.xres;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels = (calib_sensor.sensor_pixels * settings.xres) / calib_sensor.optical_res;
- settings.requested_pixels = settings.pixels;
- dev->calib_lines = dev->model->shading_lines;
- settings.lines = dev->calib_lines * (3 - ccd_size_divisor);
- settings.depth = 16;
- settings.color_filter = dev->settings.color_filter;
-
- settings.disable_interpolation = dev->settings.disable_interpolation;
- settings.threshold = dev->settings.threshold;
-
- // we don't want top offset, but we need right margin to be the same than the one for the final
- // scan
- setup_for_scan(dev, calib_sensor, &dev->reg, settings, true, false, false, false);
-
- /* used when sending shading calibration data */
- dev->calib_pixels = settings.pixels;
- dev->calib_channels = dev->session.params.channels;
- if (!dev->model->is_cis) {
- dev->calib_channels = 3;
+ unsigned calib_lines =
+ static_cast<unsigned>(dev->model->y_size_calib_mm * resolution / MM_PER_INCH);
+
+ ScanSession session;
+ session.params.xres = resolution;
+ session.params.yres = resolution;
+ session.params.startx = 0;
+ session.params.starty = 0;
+ session.params.pixels = pixels;
+ session.params.lines = calib_lines;
+ session.params.depth = 16;
+ session.params.channels = channels;
+ session.params.scan_method = dev->settings.scan_method;
+ session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
+ session.params.color_filter = dev->settings.color_filter;
+ session.params.flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA |
+ ScanFlag::IGNORE_COLOR_OFFSET |
+ ScanFlag::IGNORE_STAGGER_OFFSET;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) {
+ session.params.flags |= ScanFlag::USE_XPA;
}
+ compute_session(dev, session, calib_sensor);
+
+ dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session);
+
+ dev->calib_session = session;
/* no shading */
- dev->reg.find_reg(0x01).value &= ~REG_0x01_DVDSET;
dev->reg.find_reg(0x02).value |= REG_0x02_ACDCDIS; /* ease backtracking */
- dev->reg.find_reg(0x02).value &= ~(REG_0x02_FASTFED | REG_0x02_AGOHOME);
- dev->reg.find_reg(0x05).value &= ~REG_0x05_GMMENB;
+ dev->reg.find_reg(0x02).value &= ~REG_0x02_FASTFED;
sanei_genesys_set_motor_power(dev->reg, false);
-
- /* TODO another flag to setup regs ? */
- /* enforce needed LINCNT, getting rid of extra lines for color reordering */
- if (!dev->model->is_cis) {
- dev->reg.set24(REG_LINCNT, dev->calib_lines);
- } else {
- dev->reg.set24(REG_LINCNT, dev->calib_lines * 3);
- }
-
- /* copy reg to calib_reg */
- dev->calib_reg = dev->reg;
-
- DBG(DBG_info, "%s:\n\tdev->settings.xres=%d\n\tdev->settings.yres=%d\n", __func__,
- dev->settings.xres, dev->settings.yres);
}
bool CommandSetGl646::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
@@ -1745,109 +1852,6 @@ bool CommandSetGl646::needs_home_before_init_regs_for_scan(Genesys_Device* dev)
}
/**
- * set up registers for the actual scan. The scan's parameters are given
- * through the device settings. It allocates the scan buffers.
- */
-void CommandSetGl646::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const
-{
- DBG_HELPER(dbg);
-
- debug_dump(DBG_info, dev->settings);
-
- ScanSession session = calculate_scan_session(dev, sensor, dev->settings);
-
- init_regs_for_scan_session(dev, sensor, &dev->reg, session);
-
- /* gamma is only enabled at final scan time */
- if (dev->settings.depth < 16) {
- dev->reg.find_reg(0x05).value |= REG_0x05_GMMENB;
- }
-}
-
-/**
- * set up registers for the actual scan. The scan's parameters are given
- * through the device settings. It allocates the scan buffers.
- * @param dev scanner's device
- * @param regs registers to set up
- * @param settings settings of scan
- * @param split true if move to scan area is split from scan, false is
- * scan first moves to area
- * @param xcorrection take x geometry correction into account (fixed and detected offsets)
- * @param ycorrection take y geometry correction into account
- */
-static void setup_for_scan(Genesys_Device* dev,
- const Genesys_Sensor& sensor,
- Genesys_Register_Set*regs,
- Genesys_Settings settings,
- bool split,
- bool xcorrection,
- bool ycorrection,
- bool reverse)
-{
- DBG_HELPER(dbg);
-
- debug_dump(DBG_info, dev->settings);
-
- // compute distance to move
- float move = 0;
- // XXX STEF XXX MD5345 -> optical_ydpi, other base_ydpi => half/full step ? */
- if (!split) {
- if (!dev->model->is_sheetfed) {
- if (ycorrection) {
- move = static_cast<float>(dev->model->y_offset);
- }
-
- // add tl_y to base movement
- }
- move += static_cast<float>(settings.tl_y);
-
- if (move < 0) {
- DBG(DBG_error, "%s: overriding negative move value %f\n", __func__, move);
- move = 0;
- }
- }
- move = static_cast<float>((move * dev->motor.optical_ydpi) / MM_PER_INCH);
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
-
- float start = static_cast<float>(settings.tl_x);
- if (xcorrection) {
- if (settings.scan_method == ScanMethod::FLATBED) {
- start += static_cast<float>(dev->model->x_offset);
- } else {
- start += static_cast<float>(dev->model->x_offset_ta);
- }
- }
- start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
-
- ScanSession session;
- session.params.xres = settings.xres;
- session.params.yres = settings.yres;
- session.params.startx = static_cast<unsigned>(start);
- session.params.starty = static_cast<unsigned>(move);
- session.params.pixels = settings.pixels;
- session.params.requested_pixels = settings.requested_pixels;
- session.params.lines = settings.lines;
- session.params.depth = settings.depth;
- session.params.channels = settings.get_channels();
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = settings.scan_mode;
- session.params.color_filter = settings.color_filter;
- session.params.flags = ScanFlag::NONE;
- if (settings.scan_method == ScanMethod::TRANSPARENCY) {
- session.params.flags |= ScanFlag::USE_XPA;
- }
- if (xcorrection) {
- session.params.flags |= ScanFlag::USE_XCORRECTION;
- }
- if (reverse) {
- session.params.flags |= ScanFlag::REVERSE;
- }
- compute_session(dev, session, sensor);
-
- dev->cmd_set->init_regs_for_scan_session(dev, sensor, regs, session);
-}
-
-/**
* this function send gamma table to ASIC
*/
void CommandSetGl646::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const
@@ -1857,9 +1861,7 @@ void CommandSetGl646::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor
int address;
int bits;
- /* gamma table size */
- if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA)
- {
+ if (has_flag(dev->model->flags, ModelFlag::GAMMA_14BIT)) {
size = 16384;
bits = 14;
}
@@ -1903,45 +1905,42 @@ SensorExposure CommandSetGl646::led_calibration(Genesys_Device* dev, const Genes
{
DBG_HELPER(dbg);
(void) regs;
- int total_size;
unsigned int i, j;
int val;
int avg[3], avga, avge;
int turn;
uint16_t expr, expg, expb;
- Genesys_Settings settings;
- SANE_Int resolution;
unsigned channels = dev->settings.get_channels();
- /* get led calibration resolution */
- if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS)
- {
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- }
- else
- {
- settings.scan_mode = ScanColorMode::GRAY;
+ ScanColorMode scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
+ if (dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS) {
+ scan_mode = ScanColorMode::GRAY;
}
- resolution = get_closest_resolution(dev->model->sensor_id, sensor.optical_res, channels);
- /* offset calibration is always done in color mode */
- settings.scan_method = dev->model->default_method;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels = (sensor.sensor_pixels * resolution) / sensor.optical_res;
- settings.requested_pixels = settings.pixels;
- settings.lines = 1;
- settings.depth = 16;
- settings.color_filter = ColorFilter::RED;
+ // offset calibration is always done in color mode
+ unsigned pixels = dev->model->x_size_calib_mm * sensor.full_resolution / MM_PER_INCH;
- settings.disable_interpolation = 0;
- settings.threshold = 0;
+ ScanSession session;
+ session.params.xres = sensor.full_resolution;
+ session.params.yres = sensor.full_resolution;
+ session.params.startx = 0;
+ session.params.starty = 0;
+ session.params.pixels = pixels;
+ session.params.lines = 1;
+ session.params.depth = 16;
+ session.params.channels = channels;
+ session.params.scan_method = dev->settings.scan_method;
+ session.params.scan_mode = scan_mode;
+ session.params.color_filter = ColorFilter::RED;
+ session.params.flags = ScanFlag::DISABLE_SHADING;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) {
+ session.params.flags |= ScanFlag::USE_XPA;
+ }
+ compute_session(dev, session, sensor);
- /* colors * bytes_per_color * scan lines */
- total_size = settings.pixels * channels * 2 * 1;
+ // colors * bytes_per_color * scan lines
+ unsigned total_size = pixels * channels * 2 * 1;
std::vector<uint8_t> line(total_size);
@@ -1968,38 +1967,34 @@ SensorExposure CommandSetGl646::led_calibration(Genesys_Device* dev, const Genes
DBG(DBG_info, "%s: starting first line reading\n", __func__);
- simple_scan(dev, calib_sensor, settings, false, true, false, line, "led_calibration");
+ dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session);
+ simple_scan(dev, calib_sensor, session, false, line, "led_calibration");
if (is_testing_mode()) {
return calib_sensor.exposure;
}
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[30];
- std::snprintf(fn, 30, "gl646_led_%02d.pnm", turn);
- sanei_genesys_write_pnm_file(fn, line.data(), 16, channels, settings.pixels, 1);
- }
+ if (dbg_log_image_data()) {
+ char fn[30];
+ std::snprintf(fn, 30, "gl646_led_%02d.tiff", turn);
+ write_tiff_file(fn, line.data(), 16, channels, pixels, 1);
+ }
acceptable = true;
for (j = 0; j < channels; j++)
{
avg[j] = 0;
- for (i = 0; i < settings.pixels; i++)
- {
- if (dev->model->is_cis)
- val =
- line[i * 2 + j * 2 * settings.pixels + 1] * 256 +
- line[i * 2 + j * 2 * settings.pixels];
- else
- val =
- line[i * 2 * channels + 2 * j + 1] * 256 +
- line[i * 2 * channels + 2 * j];
- avg[j] += val;
+ for (i = 0; i < pixels; i++) {
+ if (dev->model->is_cis) {
+ val = line[i * 2 + j * 2 * pixels + 1] * 256 + line[i * 2 + j * 2 * pixels];
+ } else {
+ val = line[i * 2 * channels + 2 * j + 1] * 256 + line[i * 2 * channels + 2 * j];
+ }
+ avg[j] += val;
}
- avg[j] /= settings.pixels;
+ avg[j] /= pixels;
}
DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]);
@@ -2088,31 +2083,40 @@ static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor&
unsigned int channels;
int pass = 0;
- SANE_Int resolution;
- Genesys_Settings settings;
- unsigned int x, y, adr, min;
+ unsigned adr, min;
unsigned int bottom, black_pixels;
channels = 3;
- resolution = get_closest_resolution(dev->model->sensor_id, sensor.optical_res, channels);
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3, ScanMethod::FLATBED);
- black_pixels = (calib_sensor.black_pixels * resolution) / calib_sensor.optical_res;
- DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
-
- settings.scan_method = dev->model->default_method;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res;
- settings.requested_pixels = settings.pixels;
- settings.lines = CALIBRATION_LINES;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
+
+ // FIXME: maybe reuse `sensor`
+ const auto& calib_sensor = sanei_genesys_find_sensor(dev, sensor.full_resolution, 3,
+ ScanMethod::FLATBED);
+ black_pixels = (calib_sensor.black_pixels * sensor.full_resolution) / calib_sensor.full_resolution;
+
+ unsigned pixels = dev->model->x_size_calib_mm * sensor.full_resolution / MM_PER_INCH;
+ unsigned lines = CALIBRATION_LINES;
+
+ if (dev->model->is_cis) {
+ lines = ((lines + 2) / 3) * 3;
+ }
+
+ ScanSession session;
+ session.params.xres = sensor.full_resolution;
+ session.params.yres = sensor.full_resolution;
+ session.params.startx = 0;
+ session.params.starty = 0;
+ session.params.pixels = pixels;
+ session.params.lines = lines;
+ session.params.depth = 8;
+ session.params.channels = 3;
+ session.params.scan_method = dev->settings.scan_method;
+ session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
+ session.params.color_filter = ColorFilter::RED;
+ session.params.flags = ScanFlag::DISABLE_SHADING;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) {
+ session.params.flags |= ScanFlag::USE_XPA;
+ }
+ compute_session(dev, session, calib_sensor);
/* scan first line of data with no gain */
dev->frontend.set_gain(0, 0);
@@ -2129,27 +2133,24 @@ static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor&
dev->frontend.set_offset(0, bottom);
dev->frontend.set_offset(1, bottom);
dev->frontend.set_offset(2, bottom);
- simple_scan(dev, calib_sensor, settings, false, true, false, line,
- "ad_fe_offset_calibration");
+
+ dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session);
+ simple_scan(dev, calib_sensor, session, false, line, "ad_fe_offset_calibration");
if (is_testing_mode()) {
return;
}
- if (DBG_LEVEL >= DBG_data)
- {
- char title[30];
- std::snprintf(title, 30, "gl646_offset%03d.pnm", static_cast<int>(bottom));
- sanei_genesys_write_pnm_file (title, line.data(), 8, channels,
- settings.pixels, settings.lines);
- }
+ if (dbg_log_image_data()) {
+ char title[30];
+ std::snprintf(title, 30, "gl646_offset%03d.tiff", static_cast<int>(bottom));
+ write_tiff_file(title, line.data(), 8, channels, pixels, lines);
+ }
min = 0;
- for (y = 0; y < settings.lines; y++)
- {
- for (x = 0; x < black_pixels; x++)
- {
- adr = (x + y * settings.pixels) * channels;
+ for (unsigned y = 0; y < lines; y++) {
+ for (unsigned x = 0; x < black_pixels; x++) {
+ adr = (x + y * pixels) * channels;
if (line[adr] > min)
min = line[adr];
if (line[adr + 1] > min)
@@ -2159,7 +2160,7 @@ static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor&
}
}
- DBG(DBG_io2, "%s: pass=%d, min=%d\n", __func__, pass, min);
+ DBG(DBG_info, "%s: pass=%d, min=%d\n", __func__, pass, min);
bottom++;
}
while (pass < 128 && min == 0);
@@ -2187,9 +2188,7 @@ void CommandSetGl646::offset_calibration(Genesys_Device* dev, const Genesys_Sens
DBG_HELPER(dbg);
(void) regs;
- unsigned int channels;
int pass = 0, avg;
- Genesys_Settings settings;
int topavg, bottomavg;
int top, bottom, black_pixels;
@@ -2198,32 +2197,38 @@ void CommandSetGl646::offset_calibration(Genesys_Device* dev, const Genesys_Sens
return;
}
- DBG(DBG_proc, "%s: start\n", __func__); // TODO
-
/* setup for a RGB scan, one full sensor's width line */
/* resolution is the one from the final scan */
- channels = 3;
- int resolution = get_closest_resolution(dev->model->sensor_id, dev->settings.xres, channels);
-
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3, ScanMethod::FLATBED);
- black_pixels = (calib_sensor.black_pixels * resolution) / calib_sensor.optical_res;
+ unsigned resolution = dev->settings.xres;
+ unsigned channels = 3;
- DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
+ const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
+ ScanMethod::FLATBED);
+ black_pixels = (calib_sensor.black_pixels * resolution) / calib_sensor.full_resolution;
- settings.scan_method = dev->model->default_method;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res;
- settings.requested_pixels = settings.pixels;
- settings.lines = CALIBRATION_LINES;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
+ unsigned pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
+ unsigned lines = CALIBRATION_LINES;
+ if (dev->model->is_cis) {
+ lines = ((lines + 2) / 3) * 3;
+ }
- settings.disable_interpolation = 0;
- settings.threshold = 0;
+ ScanSession session;
+ session.params.xres = resolution;
+ session.params.yres = resolution;
+ session.params.startx = 0;
+ session.params.starty = 0;
+ session.params.pixels = pixels;
+ session.params.lines = lines;
+ session.params.depth = 8;
+ session.params.channels = channels;
+ session.params.scan_method = dev->settings.scan_method;
+ session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
+ session.params.color_filter = ColorFilter::RED;
+ session.params.flags = ScanFlag::DISABLE_SHADING;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) {
+ session.params.flags |= ScanFlag::USE_XPA;
+ }
+ compute_session(dev, session, sensor);
/* scan first line of data with no gain, but with offset from
* last calibration */
@@ -2239,38 +2244,32 @@ void CommandSetGl646::offset_calibration(Genesys_Device* dev, const Genesys_Sens
std::vector<uint8_t> first_line, second_line;
- simple_scan(dev, calib_sensor, settings, false, true, false, first_line,
- "offset_first_line");
+ dev->cmd_set->init_regs_for_scan_session(dev, sensor, &dev->reg, session);
+ simple_scan(dev, calib_sensor, session, false, first_line, "offset_first_line");
- if (DBG_LEVEL >= DBG_data)
- {
- char title[30];
- std::snprintf(title, 30, "gl646_offset%03d.pnm", bottom);
- sanei_genesys_write_pnm_file(title, first_line.data(), 8, channels,
- settings.pixels, settings.lines);
+ if (dbg_log_image_data()) {
+ char title[30];
+ std::snprintf(title, 30, "gl646_offset%03d.tiff", bottom);
+ write_tiff_file(title, first_line.data(), 8, channels, pixels, lines);
}
- bottomavg = dark_average(first_line.data(), settings.pixels, settings.lines, channels,
- black_pixels);
- DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg);
+ bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels);
+ DBG(DBG_info, "%s: bottom avg=%d\n", __func__, bottomavg);
/* now top value */
top = 231;
dev->frontend.set_offset(0, top);
dev->frontend.set_offset(1, top);
dev->frontend.set_offset(2, top);
- simple_scan(dev, calib_sensor, settings, false, true, false, second_line,
- "offset_second_line");
+ dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session);
+ simple_scan(dev, calib_sensor, session, false, second_line, "offset_second_line");
- if (DBG_LEVEL >= DBG_data)
- {
- char title[30];
- std::snprintf(title, 30, "gl646_offset%03d.pnm", top);
- sanei_genesys_write_pnm_file (title, second_line.data(), 8, channels,
- settings.pixels, settings.lines);
+ if (dbg_log_image_data()) {
+ char title[30];
+ std::snprintf(title, 30, "gl646_offset%03d.tiff", top);
+ write_tiff_file(title, second_line.data(), 8, channels, pixels, lines);
}
- topavg = dark_average(second_line.data(), settings.pixels, settings.lines, channels,
- black_pixels);
- DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg);
+ topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
+ DBG(DBG_info, "%s: top avg=%d\n", __func__, topavg);
if (is_testing_mode()) {
return;
@@ -2287,20 +2286,17 @@ void CommandSetGl646::offset_calibration(Genesys_Device* dev, const Genesys_Sens
dev->frontend.set_offset(2, (top + bottom) / 2);
// scan with no move
- simple_scan(dev, calib_sensor, settings, false, true, false, second_line,
+ dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session);
+ simple_scan(dev, calib_sensor, session, false, second_line,
"offset_calibration_i");
- if (DBG_LEVEL >= DBG_data)
- {
- char title[30];
- std::snprintf(title, 30, "gl646_offset%03d.pnm", dev->frontend.get_offset(1));
- sanei_genesys_write_pnm_file (title, second_line.data(), 8, channels,
- settings.pixels, settings.lines);
- }
+ if (dbg_log_image_data()) {
+ char title[30];
+ std::snprintf(title, 30, "gl646_offset%03d.tiff", dev->frontend.get_offset(1));
+ write_tiff_file(title, second_line.data(), 8, channels, pixels, lines);
+ }
- avg =
- dark_average (second_line.data(), settings.pixels, settings.lines, channels,
- black_pixels);
+ avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1));
/* compute new boundaries */
@@ -2322,102 +2318,6 @@ void CommandSetGl646::offset_calibration(Genesys_Device* dev, const Genesys_Sens
dev->frontend.get_offset(2));
}
-/** @brief gain calibration for Analog Device frontends
- * Alternative coarse gain calibration
- */
-static void ad_fe_coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs, int dpi)
-{
- DBG_HELPER(dbg);
- (void) sensor;
- (void) regs;
-
- unsigned int i, channels, val;
- unsigned int size, count, resolution, pass;
- float average;
- Genesys_Settings settings;
- char title[32];
-
- /* setup for a RGB scan, one full sensor's width line */
- /* resolution is the one from the final scan */
- channels = 3;
- resolution = get_closest_resolution(dev->model->sensor_id, dpi, channels);
-
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3, ScanMethod::FLATBED);
-
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
-
- settings.scan_method = dev->model->default_method;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res;
- settings.requested_pixels = settings.pixels;
- settings.lines = CALIBRATION_LINES;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
-
- size = channels * settings.pixels * settings.lines;
-
- /* start gain value */
- dev->frontend.set_gain(0, 1);
- dev->frontend.set_gain(1, 1);
- dev->frontend.set_gain(2, 1);
-
- average = 0;
- pass = 0;
-
- std::vector<uint8_t> line;
-
- // loop until each channel raises to acceptable level
- while ((average < calib_sensor.gain_white_ref) && (pass < 30)) {
- // scan with no move
- simple_scan(dev, calib_sensor, settings, false, true, false, line,
- "ad_fe_coarse_gain_calibration");
-
- /* log scanning data */
- if (DBG_LEVEL >= DBG_data)
- {
- std::sprintf(title, "gl646_alternative_gain%02d.pnm", pass);
- sanei_genesys_write_pnm_file(title, line.data(), 8, channels, settings.pixels,
- settings.lines);
- }
- pass++;
-
- /* computes white average */
- average = 0;
- count = 0;
- for (i = 0; i < size; i++)
- {
- val = line[i];
- average += val;
- count++;
- }
- average = average / count;
-
- uint8_t gain0 = dev->frontend.get_gain(0);
- // adjusts gain for the channel
- if (average < calib_sensor.gain_white_ref) {
- gain0 += 1;
- }
-
- dev->frontend.set_gain(0, gain0);
- dev->frontend.set_gain(1, gain0);
- dev->frontend.set_gain(2, gain0);
-
- DBG(DBG_proc, "%s: average = %.2f, gain = %d\n", __func__, average, gain0);
- }
-
- DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__,
- dev->frontend.get_gain(0),
- dev->frontend.get_gain(1),
- dev->frontend.get_gain(2));
-}
-
/**
* Alternative coarse gain calibration
* this on uses the settings from offset_calibration. First scan moves so
@@ -2430,76 +2330,67 @@ void CommandSetGl646::coarse_gain_calibration(Genesys_Device* dev, const Genesys
{
DBG_HELPER(dbg);
(void) dpi;
+ (void) sensor;
+ (void) regs;
- unsigned int i, j, k, channels, val, maximum, idx;
- unsigned int count, resolution, pass;
float average[3];
- Genesys_Settings settings;
char title[32];
- if (dev->model->sensor_id == SensorId::CIS_XP200) {
- return ad_fe_coarse_gain_calibration(dev, sensor, regs, sensor.optical_res);
- }
-
/* setup for a RGB scan, one full sensor's width line */
/* resolution is the one from the final scan */
- channels = 3;
+ unsigned channels = 3;
- /* we are searching a sensor resolution */
- resolution = get_closest_resolution(dev->model->sensor_id, dev->settings.xres, channels);
-
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
+ // BUG: the following comment is incorrect
+ // we are searching a sensor resolution */
+ const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->settings.xres, channels,
ScanMethod::FLATBED);
- settings.scan_method = dev->settings.scan_method;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_y = 0;
- if (settings.scan_method == ScanMethod::FLATBED)
- {
- settings.tl_x = 0;
- settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res;
+ unsigned pixels = 0;
+ float start = 0;
+ if (dev->settings.scan_method == ScanMethod::FLATBED) {
+ pixels = dev->model->x_size_calib_mm * dev->settings.xres / MM_PER_INCH;
+ } else {
+ start = dev->model->x_offset_ta;
+ pixels = static_cast<unsigned>(
+ (dev->model->x_size_ta * dev->settings.xres) / MM_PER_INCH);
}
- else
- {
- settings.tl_x = dev->model->x_offset_ta;
- settings.pixels = static_cast<unsigned>((dev->model->x_size_ta * resolution) / MM_PER_INCH);
+
+ unsigned lines = CALIBRATION_LINES;
+ // round up to multiple of 3 in case of CIS scanner
+ if (dev->model->is_cis) {
+ lines = ((lines + 2) / 3) * 3;
}
- settings.requested_pixels = settings.pixels;
- settings.lines = CALIBRATION_LINES;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
- settings.disable_interpolation = 0;
- settings.threshold = 0;
+ start = static_cast<float>((start * dev->settings.xres) / MM_PER_INCH);
+
+ ScanSession session;
+ session.params.xres = dev->settings.xres;
+ session.params.yres = dev->settings.xres;
+ session.params.startx = static_cast<unsigned>(start);
+ session.params.starty = 0;
+ session.params.pixels = pixels;
+ session.params.lines = lines;
+ session.params.depth = 8;
+ session.params.channels = channels;
+ session.params.scan_method = dev->settings.scan_method;
+ session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
+ session.params.color_filter = ColorFilter::RED;
+ session.params.flags = ScanFlag::DISABLE_SHADING;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) {
+ session.params.flags |= ScanFlag::USE_XPA;
+ }
+ compute_session(dev, session, calib_sensor);
/* start gain value */
dev->frontend.set_gain(0, 1);
dev->frontend.set_gain(1, 1);
dev->frontend.set_gain(2, 1);
- if (channels > 1)
- {
- average[0] = 0;
- average[1] = 0;
- average[2] = 0;
- idx = 0;
- }
- else
- {
- average[0] = 255;
- average[1] = 255;
- average[2] = 255;
- switch (dev->settings.color_filter) {
- case ColorFilter::RED: idx = 0; break;
- case ColorFilter::GREEN: idx = 1; break;
- case ColorFilter::BLUE: idx = 2; break;
- default: idx = 0; break; // should not happen
- }
- average[idx] = 0;
- }
- pass = 0;
+ average[0] = 0;
+ average[1] = 0;
+ average[2] = 0;
+
+ unsigned pass = 0;
std::vector<uint8_t> line;
@@ -2509,75 +2400,60 @@ void CommandSetGl646::coarse_gain_calibration(Genesys_Device* dev, const Genesys
(average[2] < calib_sensor.gain_white_ref)) && (pass < 30))
{
// scan with no move
- simple_scan(dev, calib_sensor, settings, false, true, false, line,
- "coarse_gain_calibration");
+ dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session);
+ simple_scan(dev, calib_sensor, session, false, line, "coarse_gain_calibration");
- /* log scanning data */
- if (DBG_LEVEL >= DBG_data)
- {
- std::sprintf(title, "gl646_gain%02d.pnm", pass);
- sanei_genesys_write_pnm_file(title, line.data(), 8, channels, settings.pixels,
- settings.lines);
- }
- pass++;
-
- /* average high level for each channel and compute gain
- to reach the target code
- we only use the central half of the CCD data */
- for (k = idx; k < idx + channels; k++)
- {
- /* we find the maximum white value, so we can deduce a threshold
- to average white values */
- maximum = 0;
- for (i = 0; i < settings.lines; i++)
- {
- for (j = 0; j < settings.pixels; j++)
- {
- val = line[i * channels * settings.pixels + j + k];
- if (val > maximum)
- maximum = val;
- }
- }
+ if (dbg_log_image_data()) {
+ std::sprintf(title, "gl646_gain%02d.tiff", pass);
+ write_tiff_file(title, line.data(), 8, channels, pixels, lines);
+ }
+ pass++;
+
+ // average high level for each channel and compute gain to reach the target code
+ // we only use the central half of the CCD data
+ for (unsigned k = 0; k < channels; k++) {
+
+ // we find the maximum white value, so we can deduce a threshold
+ // to average white values
+ unsigned maximum = 0;
+ for (unsigned i = 0; i < lines; i++) {
+ for (unsigned j = 0; j < pixels; j++) {
+ unsigned val = line[i * channels * pixels + j + k];
+ maximum = std::max(maximum, val);
+ }
+ }
- /* threshold */
maximum = static_cast<int>(maximum * 0.9);
- /* computes white average */
- average[k] = 0;
- count = 0;
- for (i = 0; i < settings.lines; i++)
- {
- for (j = 0; j < settings.pixels; j++)
- {
- /* averaging only white points allow us not to care about dark margins */
- val = line[i * channels * settings.pixels + j + k];
- if (val > maximum)
- {
- average[k] += val;
- count++;
- }
- }
- }
- average[k] = average[k] / count;
-
- /* adjusts gain for the channel */
- if (average[k] < calib_sensor.gain_white_ref)
- dev->frontend.set_gain(k, dev->frontend.get_gain(k) + 1);
+ // computes white average
+ average[k] = 0;
+ unsigned count = 0;
+ for (unsigned i = 0; i < lines; i++) {
+ for (unsigned j = 0; j < pixels; j++) {
+ // averaging only white points allow us not to care about dark margins
+ unsigned val = line[i * channels * pixels + j + k];
+ if (val > maximum) {
+ average[k] += val;
+ count++;
+ }
+ }
+ }
+ average[k] = average[k] / count;
- DBG(DBG_proc, "%s: channel %d, average = %.2f, gain = %d\n", __func__, k, average[k],
- dev->frontend.get_gain(k));
- }
- }
+ // adjusts gain for the channel
+ if (average[k] < calib_sensor.gain_white_ref) {
+ dev->frontend.set_gain(k, dev->frontend.get_gain(k) + 1);
+ }
- if (channels < 3) {
- dev->frontend.set_gain(1, dev->frontend.get_gain(0));
- dev->frontend.set_gain(2, dev->frontend.get_gain(0));
+ DBG(DBG_info, "%s: channel %d, average = %.2f, gain = %d\n", __func__, k, average[k],
+ dev->frontend.get_gain(k));
+ }
}
- DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__,
- dev->frontend.get_gain(0),
- dev->frontend.get_gain(1),
- dev->frontend.get_gain(2));
+ DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__,
+ dev->frontend.get_gain(0),
+ dev->frontend.get_gain(1),
+ dev->frontend.get_gain(2));
}
/**
@@ -2585,46 +2461,43 @@ void CommandSetGl646::coarse_gain_calibration(Genesys_Device* dev, const Genesys
*
*/
void CommandSetGl646::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* local_reg, int* channels,
- int* total_size) const
+ Genesys_Register_Set* local_reg) const
{
DBG_HELPER(dbg);
(void) sensor;
- Genesys_Settings settings;
- int resolution, lines;
-
dev->frontend = dev->frontend_initial;
- resolution = get_closest_resolution(dev->model->sensor_id, 300, 1);
-
+ unsigned resolution = 300;
const auto& local_sensor = sanei_genesys_find_sensor(dev, resolution, 1,
dev->settings.scan_method);
- /* set up for a half width 2 lines gray scan without moving */
- settings.scan_method = dev->model->default_method;
- settings.scan_mode = ScanColorMode::GRAY;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels = (local_sensor.sensor_pixels * resolution) / local_sensor.optical_res;
- settings.requested_pixels = settings.pixels;
- settings.lines = 2;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
-
- // setup for scan
- setup_for_scan(dev, local_sensor, &dev->reg, settings, true, false, false, false);
+ // set up for a full width 2 lines gray scan without moving
+ unsigned pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
- /* we are not going to move, so clear these bits */
- dev->reg.find_reg(0x02).value &= ~(REG_0x02_FASTFED | REG_0x02_AGOHOME);
+ ScanSession session;
+ session.params.xres = resolution;
+ session.params.yres = resolution;
+ session.params.startx = 0;
+ session.params.starty = 0;
+ session.params.pixels = pixels;
+ session.params.lines = 2;
+ session.params.depth = dev->model->bpp_gray_values.front();
+ session.params.channels = 1;
+ session.params.scan_method = dev->settings.scan_method;
+ session.params.scan_mode = ScanColorMode::GRAY;
+ session.params.color_filter = ColorFilter::RED;
+ session.params.flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) {
+ session.params.flags |= ScanFlag::USE_XPA;
+ }
+ compute_session(dev, session, local_sensor);
+
+ dev->cmd_set->init_regs_for_scan_session(dev, local_sensor, &dev->reg, session);
- /* don't enable any correction for this scan */
- dev->reg.find_reg(0x01).value &= ~REG_0x01_DVDSET;
+ /* we are not going to move, so clear these bits */
+ dev->reg.find_reg(0x02).value &= ~REG_0x02_FASTFED;
/* copy to local_reg */
*local_reg = dev->reg;
@@ -2632,66 +2505,8 @@ void CommandSetGl646::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Se
/* turn off motor during this scan */
sanei_genesys_set_motor_power(*local_reg, false);
- /* returned value to higher level warmup function */
- *channels = 1;
- lines = local_reg->get24(REG_LINCNT) + 1;
- *total_size = lines * settings.pixels;
-
// now registers are ok, write them to scanner
- gl646_set_fe(dev, local_sensor, AFE_SET, settings.xres);
- dev->interface->write_registers(*local_reg);
-}
-
-
-/*
- * this function moves head without scanning, forward, then backward
- * so that the head goes to park position.
- * as a by-product, also check for lock
- */
-static void gl646_repark_head(Genesys_Device* dev)
-{
- DBG_HELPER(dbg);
- Genesys_Settings settings;
- unsigned int expected, steps;
-
- settings.scan_method = dev->model->default_method;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- settings.xres = get_closest_resolution(dev->model->sensor_id, 75, 1);
- settings.yres = settings.xres;
- settings.tl_x = 0;
- settings.tl_y = 5;
- settings.pixels = 600;
- settings.requested_pixels = settings.pixels;
- settings.lines = 4;
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
-
- const auto& sensor = sanei_genesys_find_sensor(dev, settings.xres, 3,
- dev->model->default_method);
-
- setup_for_scan(dev, sensor, &dev->reg, settings, false, false, false, false);
-
- /* TODO seems wrong ... no effective scan */
- regs_set_optical_off(dev->model->asic_type, dev->reg);
-
- dev->interface->write_registers(dev->reg);
-
- // start scan
- dev->cmd_set->begin_scan(dev, sensor, &dev->reg, true);
-
- expected = dev->reg.get24(REG_FEEDL);
- do
- {
- dev->interface->sleep_ms(100);
- sanei_genesys_read_feed_steps (dev, &steps);
- }
- while (steps < expected);
-
- // toggle motor flag, put an huge step number and redo move backward
- dev->cmd_set->move_back_home(dev, 1);
+ gl646_set_fe(dev, local_sensor, AFE_SET, session.params.xres);
}
/* *
@@ -2731,10 +2546,11 @@ void CommandSetGl646::init(Genesys_Device* dev) const
gl646_init_regs (dev);
// Init shading data
- sanei_genesys_init_shading_data(dev, sensor, sensor.sensor_pixels);
+ sanei_genesys_init_shading_data(dev, sensor,
+ dev->model->x_size_calib_mm * sensor.full_resolution /
+ MM_PER_INCH);
- /* initial calibration reg values */
- dev->calib_reg = dev->reg;
+ dev->initial_regs = dev->reg;
}
// execute physical unit init only if cold
@@ -2787,7 +2603,7 @@ void CommandSetGl646::init(Genesys_Device* dev) const
if (dev->model->gpio_id != GpioId::HP3670 &&
dev->model->gpio_id != GpioId::HP2400)
{
- switch (sensor.optical_res)
+ switch (sensor.full_resolution)
{
case 600:
addr = 0x08200;
@@ -2810,9 +2626,6 @@ void CommandSetGl646::init(Genesys_Device* dev) const
} catch (...) {
dev->interface->bulk_read_data(0x45, dev->control, len);
}
- DBG(DBG_info, "%s: control read=0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__,
- dev->control[0], dev->control[1], dev->control[2], dev->control[3], dev->control[4],
- dev->control[5]);
sanei_usb_set_timeout (30 * 1000);
}
else
@@ -2828,104 +2641,44 @@ void CommandSetGl646::init(Genesys_Device* dev) const
/* ensure head is correctly parked, and check lock */
if (!dev->model->is_sheetfed) {
- if (dev->model->flags & GENESYS_FLAG_REPARK)
- {
- // FIXME: if repark fails, we should print an error message that the scanner is locked and
- // the user should unlock the lock. We should also rethrow with SANE_STATUS_JAMMED
- gl646_repark_head(dev);
- }
- else
- {
- move_back_home(dev, true);
- }
+ move_back_home(dev, true);
}
/* here session and device are initialized */
dev->already_initialized = true;
}
-void CommandSetGl646::move_to_ta(Genesys_Device* dev) const
-{
- DBG_HELPER(dbg);
-
- simple_move(dev, static_cast<int>(dev->model->y_offset_sensor_to_ta));
-}
-
-
-/**
- * Does a simple scan: ie no line reordering and avanced data buffering and
- * shading correction. Memory for data is allocated in this function
- * and must be freed by caller.
- * @param dev device of the scanner
- * @param settings parameters of the scan
- * @param move true if moving during scan
- * @param forward true if moving forward during scan
- * @param shading true to enable shading correction
- * @param data pointer for the 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* scan_identifier)
+ const ScanSession& session, bool move,
+ std::vector<uint8_t>& data, const char* scan_identifier)
{
- DBG_HELPER_ARGS(dbg, "move=%d, forward=%d, shading=%d", move, forward, shading);
- unsigned int size, lines, x, y, bpp;
- bool split;
-
- /* round up to multiple of 3 in case of CIS scanner */
- if (dev->model->is_cis) {
- settings.lines = ((settings.lines + 2) / 3) * 3;
+ unsigned lines = session.output_line_count;
+ if (!dev->model->is_cis) {
+ lines++;
}
- /* setup for move then scan */
- split = !(move && settings.tl_y > 0);
- setup_for_scan(dev, sensor, &dev->reg, settings, split, false, false, !forward);
+ std::size_t size = lines * session.params.pixels;
+ unsigned bpp = session.params.depth == 16 ? 2 : 1;
- /* allocate memory fo scan : LINCNT may have been adjusted for CCD reordering */
- if (dev->model->is_cis) {
- lines = dev->reg.get24(REG_LINCNT) / 3;
- } else {
- lines = dev->reg.get24(REG_LINCNT) + 1;
- }
- size = lines * settings.pixels;
- if (settings.depth == 16) {
- bpp = 2;
- } else {
- bpp = 1;
- }
- size *= bpp * settings.get_channels();
+ size *= bpp * session.params.channels;
data.clear();
data.resize(size);
- DBG(DBG_io, "%s: allocated %d bytes of memory for %d lines\n", __func__, size, lines);
-
- /* put back real line number in settings */
- settings.lines = lines;
-
// initialize frontend
- gl646_set_fe(dev, sensor, AFE_SET, settings.xres);
-
- /* no shading correction and not watch dog for simple scan */
- dev->reg.find_reg(0x01).value &= ~(REG_0x01_DVDSET | REG_0x01_DOGENB);
- if (shading) {
- dev->reg.find_reg(0x01).value |= REG_0x01_DVDSET;
- }
+ gl646_set_fe(dev, sensor, AFE_SET, session.params.xres);
- /* enable gamma table for the scan */
- dev->reg.find_reg(0x05).value |= REG_0x05_GMMENB;
+ // no watch dog for simple scan
+ dev->reg.find_reg(0x01).value &= ~REG_0x01_DOGENB;
/* one table movement for simple scan */
dev->reg.find_reg(0x02).value &= ~REG_0x02_FASTFED;
if (!move) {
- sanei_genesys_set_motor_power(dev->reg, false);
-
- /* no automatic go home if no movement */
- dev->reg.find_reg(0x02).value &= ~REG_0x02_AGOHOME;
+ sanei_genesys_set_motor_power(dev->reg, false);
}
/* no automatic go home when using XPA */
- if (settings.scan_method == ScanMethod::TRANSPARENCY) {
+ if (session.params.scan_method == ScanMethod::TRANSPARENCY) {
dev->reg.find_reg(0x02).value &= ~REG_0x02_AGOHOME;
}
@@ -2946,46 +2699,38 @@ static void simple_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
sanei_genesys_read_data_from_scanner(dev, data.data(), size);
/* in case of CIS scanner, we must reorder data */
- if (dev->model->is_cis && settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) {
- /* alloc one line sized working buffer */
- std::vector<uint8_t> buffer(settings.pixels * 3 * bpp);
-
- /* reorder one line of data and put it back to buffer */
- if (bpp == 1)
- {
- for (y = 0; y < lines; y++)
- {
- /* reorder line */
- for (x = 0; x < settings.pixels; x++)
- {
- buffer[x * 3] = data[y * settings.pixels * 3 + x];
- buffer[x * 3 + 1] = data[y * settings.pixels * 3 + settings.pixels + x];
- buffer[x * 3 + 2] = data[y * settings.pixels * 3 + 2 * settings.pixels + x];
- }
- /* copy line back */
- memcpy (data.data() + settings.pixels * 3 * y, buffer.data(),
- settings.pixels * 3);
- }
- }
- else
- {
- for (y = 0; y < lines; y++)
- {
- /* reorder line */
- for (x = 0; x < settings.pixels; x++)
- {
- buffer[x * 6] = data[y * settings.pixels * 6 + x * 2];
- buffer[x * 6 + 1] = data[y * settings.pixels * 6 + x * 2 + 1];
- buffer[x * 6 + 2] = data[y * settings.pixels * 6 + 2 * settings.pixels + x * 2];
- buffer[x * 6 + 3] = data[y * settings.pixels * 6 + 2 * settings.pixels + x * 2 + 1];
- buffer[x * 6 + 4] = data[y * settings.pixels * 6 + 4 * settings.pixels + x * 2];
- buffer[x * 6 + 5] = data[y * settings.pixels * 6 + 4 * settings.pixels + x * 2 + 1];
- }
- /* copy line back */
- memcpy (data.data() + settings.pixels * 6 * y, buffer.data(),
- settings.pixels * 6);
- }
- }
+ if (dev->model->is_cis && session.params.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) {
+ auto pixels_count = session.params.pixels;
+
+ std::vector<uint8_t> buffer(pixels_count * 3 * bpp);
+
+ if (bpp == 1) {
+ for (unsigned y = 0; y < lines; y++) {
+ // reorder line
+ for (unsigned x = 0; x < pixels_count; x++) {
+ buffer[x * 3] = data[y * pixels_count * 3 + x];
+ buffer[x * 3 + 1] = data[y * pixels_count * 3 + pixels_count + x];
+ buffer[x * 3 + 2] = data[y * pixels_count * 3 + 2 * pixels_count + x];
+ }
+ // copy line back
+ std::memcpy(data.data() + pixels_count * 3 * y, buffer.data(), pixels_count * 3);
+ }
+ } else {
+ for (unsigned y = 0; y < lines; y++) {
+ // reorder line
+ auto pixels_count = session.params.pixels;
+ for (unsigned x = 0; x < pixels_count; x++) {
+ buffer[x * 6] = data[y * pixels_count * 6 + x * 2];
+ buffer[x * 6 + 1] = data[y * pixels_count * 6 + x * 2 + 1];
+ buffer[x * 6 + 2] = data[y * pixels_count * 6 + 2 * pixels_count + x * 2];
+ buffer[x * 6 + 3] = data[y * pixels_count * 6 + 2 * pixels_count + x * 2 + 1];
+ buffer[x * 6 + 4] = data[y * pixels_count * 6 + 4 * pixels_count + x * 2];
+ buffer[x * 6 + 5] = data[y * pixels_count * 6 + 4 * pixels_count + x * 2 + 1];
+ }
+ // copy line back
+ std::memcpy(data.data() + pixels_count * 6 * y, buffer.data(),pixels_count * 6);
+ }
+ }
}
// end scan , waiting the motor to stop if needed (if moving), but without ejecting doc
@@ -2993,42 +2738,6 @@ static void simple_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
}
/**
- * 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)
-{
- DBG_HELPER_ARGS(dbg, "%d mm", distance);
- Genesys_Settings settings;
-
- unsigned resolution = sanei_genesys_get_lowest_dpi(dev);
-
- const auto& sensor = sanei_genesys_find_sensor(dev, resolution, 3, dev->model->default_method);
-
- /* TODO give a no AGOHOME flag */
- settings.scan_method = dev->model->default_method;
- settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- settings.xres = resolution;
- settings.yres = resolution;
- settings.tl_y = 0;
- settings.tl_x = 0;
- settings.pixels = (sensor.sensor_pixels * settings.xres) / sensor.optical_res;
- settings.requested_pixels = settings.pixels;
- settings.lines = static_cast<unsigned>((distance * settings.xres) / MM_PER_INCH);
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
-
- std::vector<uint8_t> data;
- simple_scan(dev, sensor, settings, true, true, false, data, "simple_move");
-}
-
-/**
* update the status of the required sensor in the scanner session
* the button fileds are used to make events 'sticky'
*/
@@ -3130,22 +2839,16 @@ void CommandSetGl646::update_hardware_sensors(Genesys_Scanner* session) const
}
/* XPA detection */
- if (dev->model->flags & GENESYS_FLAG_XPA)
- {
+ if (dev->model->has_method(ScanMethod::TRANSPARENCY)) {
switch (dev->model->gpio_id) {
case GpioId::HP3670:
case GpioId::HP2400:
/* test if XPA is plugged-in */
- if ((value & 0x40) == 0)
- {
- DBG(DBG_io, "%s: enabling XPA\n", __func__);
- session->opt[OPT_SOURCE].cap &= ~SANE_CAP_INACTIVE;
- }
- else
- {
- DBG(DBG_io, "%s: disabling XPA\n", __func__);
- session->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE;
- }
+ if ((value & 0x40) == 0) {
+ session->opt[OPT_SOURCE].cap &= ~SANE_CAP_INACTIVE;
+ } else {
+ session->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE;
+ }
break;
default:
throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type");
@@ -3153,6 +2856,11 @@ void CommandSetGl646::update_hardware_sensors(Genesys_Scanner* session) const
}
}
+void CommandSetGl646::update_home_sensor_gpio(Genesys_Device& dev) const
+{
+ DBG_HELPER(dbg);
+ (void) dev;
+}
static void write_control(Genesys_Device* dev, const Genesys_Sensor& sensor, int resolution)
{
@@ -3167,7 +2875,7 @@ static void write_control(Genesys_Device* dev, const Genesys_Sensor& sensor, int
/* MD6471/G2410/HP2300 and XP200 read/write data from an undocumented memory area which
* is after the second slope table */
- switch (sensor.optical_res)
+ switch (sensor.full_resolution)
{
case 600:
addr = 0x08200;
@@ -3203,159 +2911,9 @@ static void write_control(Genesys_Device* dev, const Genesys_Sensor& sensor, int
break;
}
- DBG(DBG_info, "%s: control write=0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, control[0], control[1],
- control[2], control[3]);
dev->interface->write_buffer(0x3c, addr, control, 4);
}
-/**
- * search for a full width black or white strip.
- * @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 CommandSetGl646::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward,
- bool black) const
-{
- DBG_HELPER(dbg);
- (void) sensor;
-
- Genesys_Settings settings;
- int res = get_closest_resolution(dev->model->sensor_id, 75, 1);
- unsigned int pass, count, found, x, y;
- char title[80];
-
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, res, 1, ScanMethod::FLATBED);
-
- /* we set up for a lowest available resolution color grey scan, full width */
- settings.scan_method = dev->model->default_method;
- settings.scan_mode = ScanColorMode::GRAY;
- settings.xres = res;
- settings.yres = res;
- settings.tl_x = 0;
- settings.tl_y = 0;
- settings.pixels = static_cast<unsigned>((dev->model->x_size * res) / MM_PER_INCH);
- settings.pixels /= calib_sensor.get_ccd_size_divisor_for_dpi(res);
- settings.requested_pixels = settings.pixels;
-
- /* 15 mm at at time */
- settings.lines = static_cast<unsigned>((15 * settings.yres) / MM_PER_INCH);
- settings.depth = 8;
- settings.color_filter = ColorFilter::RED;
-
- settings.disable_interpolation = 0;
- settings.threshold = 0;
-
- /* signals if a strip of the given color has been found */
- found = 0;
-
- /* detection pass done */
- pass = 0;
-
- std::vector<uint8_t> data;
-
- /* loop until strip is found or maximum pass number done */
- while (pass < 20 && !found)
- {
- // scan a full width strip
- simple_scan(dev, calib_sensor, settings, true, forward, false, data, "search_strip");
-
- if (is_testing_mode()) {
- return;
- }
-
- if (DBG_LEVEL >= DBG_data)
- {
- std::sprintf(title, "gl646_search_strip_%s%02d.pnm", forward ? "fwd" : "bwd", pass);
- sanei_genesys_write_pnm_file (title, data.data(), settings.depth, 1,
- settings.pixels, settings.lines);
- }
-
- /* search data to find black strip */
- /* when searching forward, we only need one line of the searched color since we
- * will scan forward. But when doing backward search, we need all the area of the
- * same color */
- if (forward)
- {
- for (y = 0; y < settings.lines && !found; y++)
- {
- count = 0;
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < settings.pixels; x++)
- {
- /* when searching for black, detect white pixels */
- if (black && data[y * settings.pixels + x] > 90)
- {
- count++;
- }
- /* when searching for white, detect black pixels */
- if (!black && data[y * settings.pixels + x] < 60)
- {
- count++;
- }
- }
-
- /* at end of line, if count >= 3%, line is not fully of the desired color
- * so we must go to next line of the buffer */
- /* count*100/pixels < 3 */
- if ((count * 100) / settings.pixels < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__,
- pass, y);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count);
- }
- }
- }
- else /* since calibration scans are done forward, we need the whole area
- to be of the required color when searching backward */
- {
- count = 0;
- for (y = 0; y < settings.lines; y++)
- {
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < settings.pixels; x++)
- {
- /* when searching for black, detect white pixels */
- if (black && data[y * settings.pixels + x] > 60)
- {
- count++;
- }
- /* when searching for white, detect black pixels */
- if (!black && data[y * settings.pixels + x] < 60)
- {
- count++;
- }
- }
- }
-
- /* at end of area, if count >= 3%, area is not fully of the desired color
- * so we must go to next buffer */
- if ((count * 100) / (settings.pixels * settings.lines) < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count);
- }
- }
- pass++;
- }
- if (found)
- {
- DBG(DBG_info, "%s: strip found\n", __func__);
- }
- else
- {
- throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white");
- }
-}
-
void CommandSetGl646::wait_for_motor_stop(Genesys_Device* dev) const
{
(void) dev;
@@ -3377,26 +2935,25 @@ ScanSession CommandSetGl646::calculate_scan_session(const Genesys_Device* dev,
{
// compute distance to move
float move = 0;
- // XXX STEF XXX MD5345 -> optical_ydpi, other base_ydpi => half/full step ? */
if (!dev->model->is_sheetfed) {
- move = static_cast<float>(dev->model->y_offset);
+ move = dev->model->y_offset;
// add tl_y to base movement
}
- move += static_cast<float>(settings.tl_y);
+ move += settings.tl_y;
if (move < 0) {
DBG(DBG_error, "%s: overriding negative move value %f\n", __func__, move);
move = 0;
}
- move = static_cast<float>((move * dev->motor.optical_ydpi) / MM_PER_INCH);
- float start = static_cast<float>(settings.tl_x);
+ move = static_cast<float>((move * dev->motor.base_ydpi) / MM_PER_INCH);
+ float start = settings.tl_x;
if (settings.scan_method == ScanMethod::FLATBED) {
- start += static_cast<float>(dev->model->x_offset);
+ start += dev->model->x_offset;
} else {
- start += static_cast<float>(dev->model->x_offset_ta);
+ start += dev->model->x_offset_ta;
}
- start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
+ start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
ScanSession session;
session.params.xres = settings.xres;
@@ -3411,7 +2968,7 @@ ScanSession CommandSetGl646::calculate_scan_session(const Genesys_Device* dev,
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = settings.scan_mode;
session.params.color_filter = settings.color_filter;
- session.params.flags = ScanFlag::USE_XCORRECTION;
+ session.params.flags = ScanFlag::AUTO_GO_HOME;
if (settings.scan_method == ScanMethod::TRANSPARENCY) {
session.params.flags |= ScanFlag::USE_XPA;
}
@@ -3427,10 +2984,5 @@ void CommandSetGl646::asic_boot(Genesys_Device *dev, bool cold) const
throw SaneException("not implemented");
}
-std::unique_ptr<CommandSet> create_gl646_cmd_set()
-{
- return std::unique_ptr<CommandSet>(new CommandSetGl646{});
-}
-
} // namespace gl646
} // namespace genesys
diff --git a/backend/genesys/gl646.h b/backend/genesys/gl646.h
index afcfa05..8ab2c96 100644
--- a/backend/genesys/gl646.h
+++ b/backend/genesys/gl646.h
@@ -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,17 +64,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs, int* channels,
- int* total_size) const override;
-
- 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_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@@ -472,8 +84,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;
@@ -489,17 +99,14 @@ public:
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
+ 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,
int size) const override;
diff --git a/backend/genesys/gl646_registers.h b/backend/genesys/gl646_registers.h
index 2fe8f19..6ee9549 100644
--- a/backend/genesys/gl646_registers.h
+++ b/backend/genesys/gl646_registers.h
@@ -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;
diff --git a/backend/genesys/gl841.cpp b/backend/genesys/gl841.cpp
index 470f9ba..731354f 100644
--- a/backend/genesys/gl841.cpp
+++ b/backend/genesys/gl841.cpp
@@ -63,315 +63,11 @@ namespace gl841 {
static int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor,
+ const MotorProfile& profile,
float slope_dpi,
- StepType scan_step_type,
int start,
int used_pixels);
-/** copy sensor specific settings */
-/* *dev : device infos
- *regs : registers to be set
- extended : do extended set up
- ccd_size_divisor: set up for half ccd resolution
- all registers 08-0B, 10-1D, 52-59 are set up. They shouldn't
- appear anywhere else but in register_ini
-
-Responsible for signals to CCD/CIS:
- CCD_CK1X (CK1INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1MTGL(0x1C),CK1LOW(0x1D),CK1MAP(0x74,0x75,0x76),CK1NEG(0x7D))
- CCD_CK2X (CK2INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1LOW(0x1D),CK1NEG(0x7D))
- CCD_CK3X (MANUAL3(0x1A),CK3INV(0x1A),CK3MTGL(0x1C),CK3LOW(0x1D),CK3MAP(0x77,0x78,0x79),CK3NEG(0x7D))
- CCD_CK4X (MANUAL3(0x1A),CK4INV(0x1A),CK4MTGL(0x1C),CK4LOW(0x1D),CK4MAP(0x7A,0x7B,0x7C),CK4NEG(0x7D))
- CCD_CPX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),CPH(0x72),CPL(0x73),CPNEG(0x7D))
- CCD_RSX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),RSH(0x70),RSL(0x71),RSNEG(0x7D))
- CCD_TGX (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPR(0x10,0x11),TGSHLD(0x1D))
- CCD_TGG (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPG(0x12,0x13),TGSHLD(0x1D))
- CCD_TGB (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPB(0x14,0x15),TGSHLD(0x1D))
- LAMP_SW (EXPR(0x10,0x11),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29))
- XPA_SW (EXPG(0x12,0x13),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29))
- LAMP_B (EXPB(0x14,0x15),LAMP_PWR(0x03))
-
-other registers:
- CISSET(0x01),CNSET(0x18),DCKSEL(0x18),SCANMOD(0x18),EXPDMY(0x19),LINECLP(0x1A),CKAREA(0x1C),TGTIME(0x1C),LINESEL(0x1E),DUMMY(0x34)
-
-Responsible for signals to AFE:
- VSMP (VSMP(0x58),VSMPW(0x58))
- BSMP (BSMP(0x59),BSMPW(0x59))
-
-other register settings depending on this:
- RHI(0x52),RLOW(0x53),GHI(0x54),GLOW(0x55),BHI(0x56),BLOW(0x57),
-
-*/
-static void sanei_gl841_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set * regs,
- bool extended, unsigned ccd_size_divisor)
-{
- DBG(DBG_proc, "%s\n", __func__);
-
- // that one is tricky at least
- for (uint16_t addr = 0x08; addr <= 0x0b; ++addr) {
- regs->set8(0x70 + addr - 0x08, sensor.custom_regs.get_value(addr));
- }
-
- // ignore registers in range [0x10..0x16)
- for (uint16_t addr = 0x16; addr < 0x1e; ++addr) {
- regs->set8(addr, sensor.custom_regs.get_value(addr));
- }
-
- // ignore registers in range [0x5b..0x5e]
- for (uint16_t addr = 0x52; addr < 0x52 + 9; ++addr) {
- regs->set8(addr, sensor.custom_regs.get_value(addr));
- }
-
- /* don't go any further if no extended setup */
- if (!extended)
- return;
-
- /* todo : add more CCD types if needed */
- /* we might want to expand the Sensor struct to have these
- 2 kind of settings */
- if (dev->model->sensor_id == SensorId::CCD_5345) {
- if (ccd_size_divisor > 1) {
- GenesysRegister* r;
- /* settings for CCD used at half is max resolution */
- r = sanei_genesys_get_address (regs, 0x70);
- r->value = 0x00;
- r = sanei_genesys_get_address (regs, 0x71);
- r->value = 0x05;
- r = sanei_genesys_get_address (regs, 0x72);
- r->value = 0x06;
- r = sanei_genesys_get_address (regs, 0x73);
- r->value = 0x08;
- r = sanei_genesys_get_address (regs, 0x18);
- r->value = 0x28;
- r = sanei_genesys_get_address (regs, 0x58);
- r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */
- }
- else
- {
- GenesysRegister* r;
- /* swap latch times */
- r = sanei_genesys_get_address (regs, 0x18);
- r->value = 0x30;
- regs->set8(0x52, sensor.custom_regs.get_value(0x55));
- regs->set8(0x53, sensor.custom_regs.get_value(0x56));
- regs->set8(0x54, sensor.custom_regs.get_value(0x57));
- regs->set8(0x55, sensor.custom_regs.get_value(0x52));
- regs->set8(0x56, sensor.custom_regs.get_value(0x53));
- regs->set8(0x57, sensor.custom_regs.get_value(0x54));
- r = sanei_genesys_get_address (regs, 0x58);
- r->value = 0x20 | (r->value & 0x03); /* VSMP=4 */
- }
- return;
- }
-
- if (dev->model->sensor_id == SensorId::CCD_HP2300) {
- /* settings for CCD used at half is max resolution */
- GenesysRegister* r;
- if (ccd_size_divisor > 1) {
- r = sanei_genesys_get_address (regs, 0x70);
- r->value = 0x16;
- r = sanei_genesys_get_address (regs, 0x71);
- r->value = 0x00;
- r = sanei_genesys_get_address (regs, 0x72);
- r->value = 0x01;
- r = sanei_genesys_get_address (regs, 0x73);
- r->value = 0x03;
- /* manual clock programming */
- r = sanei_genesys_get_address (regs, 0x1d);
- r->value |= 0x80;
- }
- else
- {
- r = sanei_genesys_get_address (regs, 0x70);
- r->value = 1;
- r = sanei_genesys_get_address (regs, 0x71);
- r->value = 3;
- r = sanei_genesys_get_address (regs, 0x72);
- r->value = 4;
- r = sanei_genesys_get_address (regs, 0x73);
- r->value = 6;
- }
- r = sanei_genesys_get_address (regs, 0x58);
- r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */
- return;
- }
-}
-
-/*
- * Set all registers LiDE 80 to default values
- * (function called only once at the beginning)
- * we are doing a special case to ease development
- */
-static void
-gl841_init_lide80 (Genesys_Device * dev)
-{
- dev->reg.init_reg(0x01, 0x82); // 0x02 = SHDAREA and no CISSET !
- dev->reg.init_reg(0x02, 0x10);
- dev->reg.init_reg(0x03, 0x50);
- dev->reg.init_reg(0x04, 0x02);
- dev->reg.init_reg(0x05, 0x4c); // 1200 DPI
- dev->reg.init_reg(0x06, 0x38); // 0x38 scanmod=1, pwrbit, GAIN4
- dev->reg.init_reg(0x07, 0x00);
- dev->reg.init_reg(0x08, 0x00);
- dev->reg.init_reg(0x09, 0x11);
- dev->reg.init_reg(0x0a, 0x00);
-
- dev->reg.init_reg(0x10, 0x40);
- dev->reg.init_reg(0x11, 0x00);
- dev->reg.init_reg(0x12, 0x40);
- dev->reg.init_reg(0x13, 0x00);
- dev->reg.init_reg(0x14, 0x40);
- dev->reg.init_reg(0x15, 0x00);
- dev->reg.init_reg(0x16, 0x00);
- dev->reg.init_reg(0x17, 0x01);
- dev->reg.init_reg(0x18, 0x00);
- dev->reg.init_reg(0x19, 0x06);
- dev->reg.init_reg(0x1a, 0x00);
- dev->reg.init_reg(0x1b, 0x00);
- dev->reg.init_reg(0x1c, 0x00);
- dev->reg.init_reg(0x1d, 0x04);
- dev->reg.init_reg(0x1e, 0x10);
- dev->reg.init_reg(0x1f, 0x04);
- dev->reg.init_reg(0x20, 0x02);
- dev->reg.init_reg(0x21, 0x10);
- dev->reg.init_reg(0x22, 0x20);
- dev->reg.init_reg(0x23, 0x20);
- dev->reg.init_reg(0x24, 0x10);
- dev->reg.init_reg(0x25, 0x00);
- dev->reg.init_reg(0x26, 0x00);
- dev->reg.init_reg(0x27, 0x00);
-
- dev->reg.init_reg(0x29, 0xff);
-
- const auto& sensor = sanei_genesys_find_sensor_any(dev);
- dev->reg.init_reg(0x2c, sensor.optical_res>>8);
- dev->reg.init_reg(0x2d, sensor.optical_res & 0xff);
- dev->reg.init_reg(0x2e, 0x80);
- dev->reg.init_reg(0x2f, 0x80);
- dev->reg.init_reg(0x30, 0x00);
- dev->reg.init_reg(0x31, 0x10);
- dev->reg.init_reg(0x32, 0x15);
- dev->reg.init_reg(0x33, 0x0e);
- dev->reg.init_reg(0x34, 0x40);
- dev->reg.init_reg(0x35, 0x00);
- dev->reg.init_reg(0x36, 0x2a);
- dev->reg.init_reg(0x37, 0x30);
- dev->reg.init_reg(0x38, 0x2a);
- dev->reg.init_reg(0x39, 0xf8);
-
- dev->reg.init_reg(0x3d, 0x00);
- dev->reg.init_reg(0x3e, 0x00);
- dev->reg.init_reg(0x3f, 0x00);
-
- dev->reg.init_reg(0x52, 0x03);
- dev->reg.init_reg(0x53, 0x07);
- dev->reg.init_reg(0x54, 0x00);
- dev->reg.init_reg(0x55, 0x00);
- dev->reg.init_reg(0x56, 0x00);
- dev->reg.init_reg(0x57, 0x00);
- dev->reg.init_reg(0x58, 0x29);
- dev->reg.init_reg(0x59, 0x69);
- dev->reg.init_reg(0x5a, 0x55);
-
- dev->reg.init_reg(0x5d, 0x20);
- dev->reg.init_reg(0x5e, 0x41);
- dev->reg.init_reg(0x5f, 0x40);
- dev->reg.init_reg(0x60, 0x00);
- dev->reg.init_reg(0x61, 0x00);
- dev->reg.init_reg(0x62, 0x00);
- dev->reg.init_reg(0x63, 0x00);
- dev->reg.init_reg(0x64, 0x00);
- dev->reg.init_reg(0x65, 0x00);
- dev->reg.init_reg(0x66, 0x00);
- dev->reg.init_reg(0x67, 0x40);
- dev->reg.init_reg(0x68, 0x40);
- dev->reg.init_reg(0x69, 0x20);
- dev->reg.init_reg(0x6a, 0x20);
- dev->reg.init_reg(0x6c, 0x00);
- dev->reg.init_reg(0x6d, 0x00);
- dev->reg.init_reg(0x6e, 0x00);
- dev->reg.init_reg(0x6f, 0x00);
- dev->reg.init_reg(0x70, 0x00);
- dev->reg.init_reg(0x71, 0x05);
- dev->reg.init_reg(0x72, 0x07);
- dev->reg.init_reg(0x73, 0x09);
- dev->reg.init_reg(0x74, 0x00);
- dev->reg.init_reg(0x75, 0x01);
- dev->reg.init_reg(0x76, 0xff);
- dev->reg.init_reg(0x77, 0x00);
- dev->reg.init_reg(0x78, 0x0f);
- dev->reg.init_reg(0x79, 0xf0);
- dev->reg.init_reg(0x7a, 0xf0);
- dev->reg.init_reg(0x7b, 0x00);
- dev->reg.init_reg(0x7c, 0x1e);
- dev->reg.init_reg(0x7d, 0x11);
- dev->reg.init_reg(0x7e, 0x00);
- dev->reg.init_reg(0x7f, 0x50);
- dev->reg.init_reg(0x80, 0x00);
- dev->reg.init_reg(0x81, 0x00);
- dev->reg.init_reg(0x82, 0x0f);
- dev->reg.init_reg(0x83, 0x00);
- dev->reg.init_reg(0x84, 0x0e);
- dev->reg.init_reg(0x85, 0x00);
- dev->reg.init_reg(0x86, 0x0d);
- dev->reg.init_reg(0x87, 0x02);
- dev->reg.init_reg(0x88, 0x00);
- dev->reg.init_reg(0x89, 0x00);
-
- for (const auto& reg : dev->gpo.regs) {
- dev->reg.set8(reg.address, reg.value);
- }
-
- // specific scanner settings, clock and gpio first
- // FIXME: remove the dummy reads as we don't use the values
- if (!is_testing_mode()) {
- dev->interface->read_register(REG_0x6B);
- }
- dev->interface->write_register(REG_0x6B, 0x0c);
- dev->interface->write_register(0x06, 0x10);
- dev->interface->write_register(REG_0x6E, 0x6d);
- dev->interface->write_register(REG_0x6F, 0x80);
- dev->interface->write_register(REG_0x6B, 0x0e);
- if (!is_testing_mode()) {
- dev->interface->read_register(REG_0x6C);
- }
- dev->interface->write_register(REG_0x6C, 0x00);
- if (!is_testing_mode()) {
- dev->interface->read_register(REG_0x6D);
- }
- dev->interface->write_register(REG_0x6D, 0x8f);
- if (!is_testing_mode()) {
- dev->interface->read_register(REG_0x6B);
- }
- dev->interface->write_register(REG_0x6B, 0x0e);
- if (!is_testing_mode()) {
- dev->interface->read_register(REG_0x6B);
- }
- dev->interface->write_register(REG_0x6B, 0x0e);
- if (!is_testing_mode()) {
- dev->interface->read_register(REG_0x6B);
- }
- dev->interface->write_register(REG_0x6B, 0x0a);
- if (!is_testing_mode()) {
- dev->interface->read_register(REG_0x6B);
- }
- dev->interface->write_register(REG_0x6B, 0x02);
- if (!is_testing_mode()) {
- dev->interface->read_register(REG_0x6B);
- }
- dev->interface->write_register(REG_0x6B, 0x06);
-
- dev->interface->write_0x8c(0x10, 0x94);
- dev->interface->write_register(0x09, 0x10);
-
- // FIXME: the following code originally changed 0x6b, but due to bug the 0x6c register was
- // effectively changed. The current behavior matches the old code, but should probably be fixed.
- dev->reg.find_reg(0x6c).value |= REG_0x6B_GPO18;
- dev->reg.find_reg(0x6c).value &= ~REG_0x6B_GPO17;
-
- sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 0, 1);
-}
-
/*
* Set all registers to default values
* (function called only once at the beginning)
@@ -379,139 +75,232 @@ gl841_init_lide80 (Genesys_Device * dev)
static void
gl841_init_registers (Genesys_Device * dev)
{
- int addr;
-
- DBG(DBG_proc, "%s\n", __func__);
-
- dev->reg.clear();
- if (dev->model->model_id == ModelId::CANON_LIDE_80) {
- gl841_init_lide80(dev);
- return ;
- }
-
- for (addr = 1; addr <= 0x0a; addr++) {
- dev->reg.init_reg(addr, 0);
- }
- for (addr = 0x10; addr <= 0x27; addr++) {
- dev->reg.init_reg(addr, 0);
- }
- dev->reg.init_reg(0x29, 0);
- for (addr = 0x2c; addr <= 0x39; addr++)
- dev->reg.init_reg(addr, 0);
- for (addr = 0x3d; addr <= 0x3f; addr++)
- dev->reg.init_reg(addr, 0);
- for (addr = 0x52; addr <= 0x5a; addr++)
- dev->reg.init_reg(addr, 0);
- for (addr = 0x5d; addr <= 0x87; addr++)
- dev->reg.init_reg(addr, 0);
-
+ DBG_HELPER(dbg);
- dev->reg.find_reg(0x01).value = 0x20; /* (enable shading), CCD, color, 1M */
+ dev->reg.init_reg(0x01, 0x20);
if (dev->model->is_cis) {
dev->reg.find_reg(0x01).value |= REG_0x01_CISSET;
} else {
dev->reg.find_reg(0x01).value &= ~REG_0x01_CISSET;
}
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x01, 0x82);
+ }
- dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */
- dev->reg.find_reg(0x02).value |= REG_0x02_AGOHOME;
- sanei_genesys_set_motor_power(dev->reg, true);
- dev->reg.find_reg(0x02).value |= REG_0x02_FASTFED;
-
- dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */
- dev->reg.find_reg(0x03).value |= REG_0x03_AVEENB;
+ dev->reg.init_reg(0x02, 0x38);
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x02, 0x10);
+ }
- if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) {
- // AD front end
- dev->reg.find_reg(0x04).value = (2 << REG_0x04S_AFEMOD) | 0x02;
+ dev->reg.init_reg(0x03, 0x5f);
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x03, 0x50);
}
- else /* Wolfson front end */
- {
- dev->reg.find_reg(0x04).value |= 1 << REG_0x04S_AFEMOD;
+
+ dev->reg.init_reg(0x04, 0x10);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600) {
+ dev->reg.init_reg(0x04, 0x22);
+ } else if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x04, 0x02);
}
- const auto& sensor = sanei_genesys_find_sensor_any(dev);
+ const auto& sensor = sanei_genesys_find_sensor_any(dev);
- dev->reg.find_reg(0x05).value = 0x00; /* disable gamma, 24 clocks/pixel */
+ dev->reg.init_reg(0x05, 0x00); // disable gamma, 24 clocks/pixel
- unsigned dpihw = 0;
- if (sensor.sensor_pixels < 0x1500) {
- dpihw = 600;
- } else if (sensor.sensor_pixels < 0x2a80) {
- dpihw = 1200;
- } else if (sensor.sensor_pixels < 0x5400) {
- dpihw = 2400;
- } else {
- throw SaneException("Cannot handle sensor pixel count %d", sensor.sensor_pixels);
- }
- sanei_genesys_set_dpihw(dev->reg, sensor, dpihw);
+ sanei_genesys_set_dpihw(dev->reg, sensor.register_dpihw);
- dev->reg.find_reg(0x06).value |= REG_0x06_PWRBIT;
- dev->reg.find_reg(0x06).value |= REG_0x06_GAIN4;
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x05, 0x4c);
+ }
- /* XP300 CCD needs different clock and clock/pixels values */
- if (dev->model->sensor_id != SensorId::CCD_XP300 &&
- dev->model->sensor_id != SensorId::CCD_DP685 &&
- dev->model->sensor_id != SensorId::CCD_PLUSTEK_OPTICPRO_3600)
- {
- dev->reg.find_reg(0x06).value |= 0 << REG_0x06S_SCANMOD;
- dev->reg.find_reg(0x09).value |= 1 << REG_0x09S_CLKSET;
+ dev->reg.init_reg(0x06, 0x18);
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x06, 0x38);
}
- else
+ if (dev->model->model_id == ModelId::VISIONEER_STROBE_XP300 ||
+ dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_485 ||
+ dev->model->model_id == ModelId::DCT_DOCKETPORT_487 ||
+ dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_685 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600)
{
- dev->reg.find_reg(0x06).value |= 0x05 << REG_0x06S_SCANMOD; /* 15 clocks/pixel */
- dev->reg.find_reg(0x09).value = 0; /* 24 MHz CLKSET */
+ dev->reg.init_reg(0x06, 0xb8);
}
- dev->reg.find_reg(0x1e).value = 0xf0; /* watch-dog time */
-
- dev->reg.find_reg(0x17).value |= 1 << REG_0x17S_TGW;
-
- dev->reg.find_reg(0x19).value = 0x50;
-
- dev->reg.find_reg(0x1d).value |= 1 << REG_0x1DS_TGSHLD;
-
- dev->reg.find_reg(0x1e).value |= 1 << REG_0x1ES_WDTIME;
-
-/*SCANFED*/
- dev->reg.find_reg(0x1f).value = 0x01;
+ dev->reg.init_reg(0x07, 0x00);
+ dev->reg.init_reg(0x08, 0x00);
-/*BUFSEL*/
- dev->reg.find_reg(0x20).value = 0x20;
+ dev->reg.init_reg(0x09, 0x10);
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x09, 0x11);
+ }
+ if (dev->model->model_id == ModelId::VISIONEER_STROBE_XP300 ||
+ dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_485 ||
+ dev->model->model_id == ModelId::DCT_DOCKETPORT_487 ||
+ dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_685 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600)
+ {
+ dev->reg.init_reg(0x09, 0x00);
+ }
+ dev->reg.init_reg(0x0a, 0x00);
-/*LAMPPWM*/
- dev->reg.find_reg(0x29).value = 0xff;
+ // EXPR[0:15], EXPG[0:15], EXPB[0:15]: Exposure time settings
+ dev->reg.init_reg(0x10, 0x00); // SENSOR_DEF
+ dev->reg.init_reg(0x11, 0x00); // SENSOR_DEF
+ dev->reg.init_reg(0x12, 0x00); // SENSOR_DEF
+ dev->reg.init_reg(0x13, 0x00); // SENSOR_DEF
+ dev->reg.init_reg(0x14, 0x00); // SENSOR_DEF
+ dev->reg.init_reg(0x15, 0x00); // SENSOR_DEF
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x10, 0x40);
+ dev->reg.init_reg(0x11, 0x00);
+ dev->reg.init_reg(0x12, 0x40);
+ dev->reg.init_reg(0x13, 0x00);
+ dev->reg.init_reg(0x14, 0x40);
+ dev->reg.init_reg(0x15, 0x00);
+ }
+
+ dev->reg.init_reg(0x16, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x17, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x18, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x19, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x1a, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x1b, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x1c, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x1d, 0x01); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x1e, 0xf0);
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x1e, 0x10);
+ }
+ dev->reg.init_reg(0x1f, 0x01);
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x1f, 0x04);
+ }
+ dev->reg.init_reg(0x20, 0x20);
+ dev->reg.init_reg(0x21, 0x01);
+ dev->reg.init_reg(0x22, 0x01);
+ dev->reg.init_reg(0x23, 0x01);
+ dev->reg.init_reg(0x24, 0x01);
+ dev->reg.init_reg(0x25, 0x00);
+ dev->reg.init_reg(0x26, 0x00);
+ dev->reg.init_reg(0x27, 0x00);
+ dev->reg.init_reg(0x29, 0xff);
-/*BWHI*/
- dev->reg.find_reg(0x2e).value = 0x80;
+ dev->reg.init_reg(0x2c, 0x00);
+ dev->reg.init_reg(0x2d, 0x00);
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x2c, sensor.full_resolution >> 8);
+ dev->reg.init_reg(0x2d, sensor.full_resolution & 0xff);
+ }
+ dev->reg.init_reg(0x2e, 0x80);
+ dev->reg.init_reg(0x2f, 0x80);
-/*BWLOW*/
- dev->reg.find_reg(0x2f).value = 0x80;
+ dev->reg.init_reg(0x30, 0x00);
+ dev->reg.init_reg(0x31, 0x00);
+ dev->reg.init_reg(0x32, 0x00);
+ dev->reg.init_reg(0x33, 0x00);
+ dev->reg.init_reg(0x34, 0x00);
+ dev->reg.init_reg(0x35, 0x00);
+ dev->reg.init_reg(0x36, 0x00);
+ dev->reg.init_reg(0x37, 0x00);
+ dev->reg.init_reg(0x38, 0x4f);
+ dev->reg.init_reg(0x39, 0xc1);
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x31, 0x10);
+ dev->reg.init_reg(0x32, 0x15);
+ dev->reg.init_reg(0x33, 0x0e);
+ dev->reg.init_reg(0x34, 0x40);
+ dev->reg.init_reg(0x35, 0x00);
+ dev->reg.init_reg(0x36, 0x2a);
+ dev->reg.init_reg(0x37, 0x30);
+ dev->reg.init_reg(0x38, 0x2a);
+ dev->reg.init_reg(0x39, 0xf8);
+ }
-/*LPERIOD*/
- dev->reg.find_reg(0x38).value = 0x4f;
- dev->reg.find_reg(0x39).value = 0xc1;
+ dev->reg.init_reg(0x3d, 0x00);
+ dev->reg.init_reg(0x3e, 0x00);
+ dev->reg.init_reg(0x3f, 0x00);
-/*VSMPW*/
- dev->reg.find_reg(0x58).value |= 3 << REG_0x58S_VSMPW;
+ dev->reg.init_reg(0x52, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x53, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x54, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x55, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x56, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x57, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x58, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x59, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x5a, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
-/*BSMPW*/
- dev->reg.find_reg(0x59).value |= 3 << REG_0x59S_BSMPW;
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x5d, 0x20);
+ dev->reg.init_reg(0x5e, 0x41);
+ dev->reg.init_reg(0x5f, 0x40);
+ dev->reg.init_reg(0x60, 0x00);
+ dev->reg.init_reg(0x61, 0x00);
+ dev->reg.init_reg(0x62, 0x00);
+ dev->reg.init_reg(0x63, 0x00);
+ dev->reg.init_reg(0x64, 0x00);
+ dev->reg.init_reg(0x65, 0x00);
+ dev->reg.init_reg(0x66, 0x00);
+ dev->reg.init_reg(0x67, 0x40);
+ dev->reg.init_reg(0x68, 0x40);
+ dev->reg.init_reg(0x69, 0x20);
+ dev->reg.init_reg(0x6a, 0x20);
+ dev->reg.init_reg(0x6c, 0x00);
+ dev->reg.init_reg(0x6d, 0x00);
+ dev->reg.init_reg(0x6e, 0x00);
+ dev->reg.init_reg(0x6f, 0x00);
+ } else {
+ for (unsigned addr = 0x5d; addr <= 0x6f; addr++) {
+ dev->reg.init_reg(addr, 0);
+ }
+ dev->reg.init_reg(0x5e, 0x02);
+ if (dev->model->model_id == ModelId::CANON_LIDE_60) {
+ dev->reg.init_reg(0x66, 0xff);
+ }
+ }
-/*RLCSEL*/
- dev->reg.find_reg(0x5a).value |= REG_0x5A_RLCSEL;
+ dev->reg.init_reg(0x70, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x71, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x72, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x73, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
-/*STOPTIM*/
- dev->reg.find_reg(0x5e).value |= 0x2 << REG_0x5ES_STOPTIM;
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ dev->reg.init_reg(0x74, 0x00);
+ dev->reg.init_reg(0x75, 0x01);
+ dev->reg.init_reg(0x76, 0xff);
+ dev->reg.init_reg(0x77, 0x00);
+ dev->reg.init_reg(0x78, 0x0f);
+ dev->reg.init_reg(0x79, 0xf0);
+ dev->reg.init_reg(0x7a, 0xf0);
+ dev->reg.init_reg(0x7b, 0x00);
+ dev->reg.init_reg(0x7c, 0x1e);
+ dev->reg.init_reg(0x7d, 0x11);
+ dev->reg.init_reg(0x7e, 0x00);
+ dev->reg.init_reg(0x7f, 0x50);
+ dev->reg.init_reg(0x80, 0x00);
+ dev->reg.init_reg(0x81, 0x00);
+ dev->reg.init_reg(0x82, 0x0f);
+ dev->reg.init_reg(0x83, 0x00);
+ dev->reg.init_reg(0x84, 0x0e);
+ dev->reg.init_reg(0x85, 0x00);
+ dev->reg.init_reg(0x86, 0x0d);
+ dev->reg.init_reg(0x87, 0x02);
+ dev->reg.init_reg(0x88, 0x00);
+ dev->reg.init_reg(0x89, 0x00);
+ } else {
+ for (unsigned addr = 0x74; addr <= 0x87; addr++) {
+ dev->reg.init_reg(addr, 0);
+ }
+ }
- sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 0, 1);
+ scanner_setup_sensor(*dev, sensor, dev->reg);
// set up GPIO
for (const auto& reg : dev->gpo.regs) {
dev->reg.set8(reg.address, reg.value);
}
- /* TODO there is a switch calling to be written here */
if (dev->model->gpio_id == GpioId::CANON_LIDE_35) {
dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO18;
dev->reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17;
@@ -523,70 +312,43 @@ gl841_init_registers (Genesys_Device * dev)
if (dev->model->gpio_id == GpioId::DP685) {
/* REG_0x6B_GPO18 lights on green led */
- dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17|REG_0x6B_GPO18;
+ dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17 | REG_0x6B_GPO18;
}
- DBG(DBG_proc, "%s complete\n", __func__);
-}
-
-// Send slope table for motor movement slope_table in machine byte order
-static void gl841_send_slope_table(Genesys_Device* dev, int table_nr,
- const std::vector<uint16_t>& slope_table,
- int steps)
-{
- DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps);
- int dpihw;
- int start_address;
- char msg[4000];
-/*#ifdef WORDS_BIGENDIAN*/
- int i;
-/*#endif*/
-
- dpihw = dev->reg.find_reg(0x05).value >> 6;
-
- if (dpihw == 0) /* 600 dpi */
- start_address = 0x08000;
- else if (dpihw == 1) /* 1200 dpi */
- start_address = 0x10000;
- else if (dpihw == 2) /* 2400 dpi */
- start_address = 0x20000;
- else {
- throw SaneException("Unexpected dpihw");
- }
-
- std::vector<uint8_t> table(steps * 2);
- for(i = 0; i < steps; i++) {
- table[i * 2] = slope_table[i] & 0xff;
- table[i * 2 + 1] = slope_table[i] >> 8;
- }
-
- if (DBG_LEVEL >= DBG_io)
- {
- std::sprintf(msg, "write slope %d (%d)=", table_nr, steps);
- for (i = 0; i < steps; i++) {
- std::sprintf (msg+strlen(msg), ",%d", slope_table[i]);
- }
- DBG(DBG_io, "%s: %s\n", __func__, msg);
- }
-
- if (dev->interface->is_mock()) {
- dev->interface->record_slope_table(table_nr, slope_table);
+ if (dev->model->model_id == ModelId::CANON_LIDE_80) {
+ // specific scanner settings, clock and gpio first
+ dev->interface->write_register(REG_0x6B, 0x0c);
+ dev->interface->write_register(0x06, 0x10);
+ dev->interface->write_register(REG_0x6E, 0x6d);
+ dev->interface->write_register(REG_0x6F, 0x80);
+ dev->interface->write_register(REG_0x6B, 0x0e);
+ dev->interface->write_register(REG_0x6C, 0x00);
+ dev->interface->write_register(REG_0x6D, 0x8f);
+ dev->interface->write_register(REG_0x6B, 0x0e);
+ dev->interface->write_register(REG_0x6B, 0x0e);
+ dev->interface->write_register(REG_0x6B, 0x0a);
+ dev->interface->write_register(REG_0x6B, 0x02);
+ dev->interface->write_register(REG_0x6B, 0x06);
+
+ dev->interface->write_0x8c(0x10, 0x94);
+ dev->interface->write_register(0x09, 0x10);
+
+ // FIXME: the following code originally changed 0x6b, but due to bug the 0x6c register was
+ // effectively changed. The current behavior matches the old code, but should probably be fixed.
+ dev->reg.find_reg(0x6c).value |= REG_0x6B_GPO18;
+ dev->reg.find_reg(0x6c).value &= ~REG_0x6B_GPO17;
}
- dev->interface->write_buffer(0x3c, start_address + table_nr * 0x200, table.data(), steps * 2);
}
static void gl841_set_lide80_fe(Genesys_Device* dev, uint8_t set)
{
DBG_HELPER(dbg);
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s(): setting DAC %u\n", __func__,
- static_cast<unsigned>(dev->model->adc_id));
-
- dev->frontend = dev->frontend_initial;
+ if (set == AFE_INIT) {
+ dev->frontend = dev->frontend_initial;
- // write them to analog frontend
+ // BUG: the following code does not make sense. The addresses are different than AFE_SET
+ // case
dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x01));
dev->interface->write_fe_register(0x06, dev->frontend.regs.get_value(0x02));
@@ -611,11 +373,7 @@ static void gl841_set_ad_fe(Genesys_Device* dev, uint8_t set)
return;
}
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s(): setting DAC %u\n", __func__,
- static_cast<unsigned>(dev->model->adc_id));
-
+ if (set == AFE_INIT) {
dev->frontend = dev->frontend_initial;
// write them to analog frontend
@@ -674,15 +432,11 @@ void CommandSetGl841::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
throw SaneException("unsupported frontend type %d", frontend_type);
}
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s(): setting DAC %u\n", __func__,
- static_cast<unsigned>(dev->model->adc_id));
- dev->frontend = dev->frontend_initial;
+ if (set == AFE_INIT) {
+ dev->frontend = dev->frontend_initial;
// reset only done on init
dev->interface->write_fe_register(0x04, 0x80);
- DBG(DBG_proc, "%s(): frontend reset complete\n", __func__);
}
@@ -712,71 +466,34 @@ void CommandSetGl841::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
}
}
-enum MotorAction {
- MOTOR_ACTION_FEED = 1,
- MOTOR_ACTION_GO_HOME = 2,
- MOTOR_ACTION_HOME_FREE = 3
-};
-
// @brief turn off motor
static void gl841_init_motor_regs_off(Genesys_Register_Set* reg, unsigned int scan_lines)
{
DBG_HELPER_ARGS(dbg, "scan_lines=%d", scan_lines);
unsigned int feedl;
- GenesysRegister* r;
feedl = 2;
- r = sanei_genesys_get_address (reg, 0x3d);
- r->value = (feedl >> 16) & 0xf;
- r = sanei_genesys_get_address (reg, 0x3e);
- r->value = (feedl >> 8) & 0xff;
- r = sanei_genesys_get_address (reg, 0x3f);
- r->value = feedl & 0xff;
- r = sanei_genesys_get_address (reg, 0x5e);
- r->value &= ~0xe0;
-
- r = sanei_genesys_get_address (reg, 0x25);
- r->value = (scan_lines >> 16) & 0xf;
- r = sanei_genesys_get_address (reg, 0x26);
- r->value = (scan_lines >> 8) & 0xff;
- r = sanei_genesys_get_address (reg, 0x27);
- r->value = scan_lines & 0xff;
-
- r = sanei_genesys_get_address (reg, 0x02);
- r->value &= ~0x01; /*LONGCURV OFF*/
- r->value &= ~0x80; /*NOT_HOME OFF*/
-
- r->value &= ~0x10;
-
- r->value &= ~0x06;
-
- r->value &= ~0x08;
+ reg->set8(0x3d, (feedl >> 16) & 0xf);
+ reg->set8(0x3e, (feedl >> 8) & 0xff);
+ reg->set8(0x3f, feedl & 0xff);
+ reg->find_reg(0x5e).value &= ~0xe0;
- r->value &= ~0x20;
+ reg->set8(0x25, (scan_lines >> 16) & 0xf);
+ reg->set8(0x26, (scan_lines >> 8) & 0xff);
+ reg->set8(0x27, scan_lines & 0xff);
- r->value &= ~0x40;
+ reg->set8(0x02, 0x00);
- r = sanei_genesys_get_address (reg, 0x67);
- r->value = 0x3f;
+ reg->set8(0x67, 0x3f);
+ reg->set8(0x68, 0x3f);
- r = sanei_genesys_get_address (reg, 0x68);
- r->value = 0x3f;
+ reg->set8(REG_STEPNO, 1);
+ reg->set8(REG_FASTNO, 1);
- r = sanei_genesys_get_address(reg, REG_STEPNO);
- r->value = 0;
-
- r = sanei_genesys_get_address(reg, REG_FASTNO);
- r->value = 0;
-
- r = sanei_genesys_get_address (reg, 0x69);
- r->value = 0;
-
- r = sanei_genesys_get_address (reg, 0x6a);
- r->value = 0;
-
- r = sanei_genesys_get_address (reg, 0x5f);
- r->value = 0;
+ reg->set8(0x69, 1);
+ reg->set8(0x6a, 1);
+ reg->set8(0x5f, 1);
}
/** @brief write motor table frequency
@@ -814,207 +531,122 @@ uint8_t *table;
table=tdefault;
}
dev->interface->write_register(0x66, 0x00);
- dev->interface->write_gamma(0x28, 0xc000, table, 128,
- ScannerInterface::FLAG_SWAP_REGISTERS);
+ dev->interface->write_gamma(0x28, 0xc000, table, 128);
dev->interface->write_register(0x5b, 0x00);
dev->interface->write_register(0x5c, 0x00);
}
}
-
-static void gl841_init_motor_regs(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* reg, unsigned int feed_steps,/*1/base_ydpi*/
- /*maybe float for half/quarter step resolution?*/
- unsigned int action, MotorFlag flags)
+static void gl841_init_motor_regs_feed(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set* reg, unsigned int feed_steps,/*1/base_ydpi*/
+ ScanFlag flags)
{
- DBG_HELPER_ARGS(dbg, "feed_steps=%d, action=%d, flags=%x", feed_steps, action,
- static_cast<unsigned>(flags));
- unsigned int fast_exposure = 0;
+ DBG_HELPER_ARGS(dbg, "feed_steps=%d, flags=%x", feed_steps, static_cast<unsigned>(flags));
+ unsigned step_multiplier = 2;
int use_fast_fed = 0;
unsigned int feedl;
- GenesysRegister* r;
/*number of scan lines to add in a scan_lines line*/
{
std::vector<uint16_t> table;
table.resize(256, 0xffff);
- gl841_send_slope_table(dev, 0, table, 256);
- gl841_send_slope_table(dev, 1, table, 256);
- gl841_send_slope_table(dev, 2, table, 256);
- gl841_send_slope_table(dev, 3, table, 256);
- gl841_send_slope_table(dev, 4, table, 256);
+ scanner_send_slope_table(dev, sensor, 0, table);
+ scanner_send_slope_table(dev, sensor, 1, table);
+ scanner_send_slope_table(dev, sensor, 2, table);
+ scanner_send_slope_table(dev, sensor, 3, table);
+ scanner_send_slope_table(dev, sensor, 4, table);
}
gl841_write_freq(dev, dev->motor.base_ydpi / 4);
- if (action == MOTOR_ACTION_FEED || action == MOTOR_ACTION_GO_HOME) {
- /* FEED and GO_HOME can use fastest slopes available */
- fast_exposure = gl841_exposure_time(dev, sensor,
- dev->motor.base_ydpi / 4,
- StepType::FULL,
- 0,
- 0);
- DBG(DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure);
- }
+ // FIXME: use proper scan session
+ ScanSession session;
+ session.params.yres = dev->motor.base_ydpi;
+ session.params.scan_method = dev->model->default_method;
- if (action == MOTOR_ACTION_HOME_FREE) {
-/* HOME_FREE must be able to stop in one step, so do not try to get faster */
- fast_exposure = dev->motor.get_slope(StepType::FULL).max_speed_w;
+ const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
+ if (fast_profile == nullptr) {
+ fast_profile = get_motor_profile_ptr(dev->motor.profiles, 0, session);
}
+ auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
+ *fast_profile);
- auto fast_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor,
- StepType::FULL, fast_exposure,
- dev->motor.base_ydpi / 4);
-
- feedl = feed_steps - fast_table.steps_count * 2;
+ // BUG: fast table is counted in base_ydpi / 4
+ feedl = feed_steps - fast_table.table.size() * 2;
use_fast_fed = 1;
+ if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
+ use_fast_fed = false;
+ }
-/* all needed slopes available. we did even decide which mode to use.
- what next?
- - transfer slopes
-SCAN:
-flags \ use_fast_fed ! 0 1
-------------------------\--------------------
- 0 ! 0,1,2 0,1,2,3
-MotorFlag::AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4
-OFF: none
-FEED: 3
-GO_HOME: 3
-HOME_FREE: 3
- - setup registers
- * slope specific registers (already done)
- * DECSEL for HOME_FREE/GO_HOME/SCAN
- * FEEDL
- * MTRREV
- * MTRPWR
- * FASTFED
- * STEPSEL
- * MTRPWM
- * FSTPSEL
- * FASTPWM
- * HOMENEG
- * BWDSTEP
- * FWDSTEP
- * Z1
- * Z2
- */
+ reg->set8(0x3d, (feedl >> 16) & 0xf);
+ reg->set8(0x3e, (feedl >> 8) & 0xff);
+ reg->set8(0x3f, feedl & 0xff);
+ reg->find_reg(0x5e).value &= ~0xe0;
- r = sanei_genesys_get_address(reg, 0x3d);
- r->value = (feedl >> 16) & 0xf;
- r = sanei_genesys_get_address(reg, 0x3e);
- r->value = (feedl >> 8) & 0xff;
- r = sanei_genesys_get_address(reg, 0x3f);
- r->value = feedl & 0xff;
- r = sanei_genesys_get_address(reg, 0x5e);
- r->value &= ~0xe0;
-
- r = sanei_genesys_get_address(reg, 0x25);
- r->value = 0;
- r = sanei_genesys_get_address(reg, 0x26);
- r->value = 0;
- r = sanei_genesys_get_address(reg, 0x27);
- r->value = 0;
-
- r = sanei_genesys_get_address(reg, 0x02);
- r->value &= ~0x01; /*LONGCURV OFF*/
- r->value &= ~0x80; /*NOT_HOME OFF*/
-
- r->value |= 0x10;
-
- if (action == MOTOR_ACTION_GO_HOME)
- r->value |= 0x06;
- else
- r->value &= ~0x06;
+ reg->set8(0x25, 0);
+ reg->set8(0x26, 0);
+ reg->set8(0x27, 0);
+
+ reg->find_reg(0x02).value &= ~0x01; /*LONGCURV OFF*/
+ reg->find_reg(0x02).value &= ~0x80; /*NOT_HOME OFF*/
+
+ reg->find_reg(0x02).value |= REG_0x02_MTRPWR;
if (use_fast_fed)
- r->value |= 0x08;
+ reg->find_reg(0x02).value |= 0x08;
else
- r->value &= ~0x08;
+ reg->find_reg(0x02).value &= ~0x08;
- if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) {
- r->value |= 0x20;
+ if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
+ reg->find_reg(0x02).value |= 0x20;
} else {
- r->value &= ~0x20;
+ reg->find_reg(0x02).value &= ~0x20;
}
- r->value &= ~0x40;
+ reg->find_reg(0x02).value &= ~0x40;
- if (has_flag(flags, MotorFlag::REVERSE)) {
- r->value |= REG_0x02_MTRREV;
+ if (has_flag(flags, ScanFlag::REVERSE)) {
+ reg->find_reg(0x02).value |= REG_0x02_MTRREV;
+ } else {
+ reg->find_reg(0x02).value &= ~REG_0x02_MTRREV;
}
- gl841_send_slope_table(dev, 3, fast_table.table, 256);
+ scanner_send_slope_table(dev, sensor, 3, fast_table.table);
- r = sanei_genesys_get_address(reg, 0x67);
- r->value = 0x3f;
-
- r = sanei_genesys_get_address(reg, 0x68);
- r->value = 0x3f;
-
- r = sanei_genesys_get_address(reg, REG_STEPNO);
- r->value = 0;
-
- r = sanei_genesys_get_address(reg, REG_FASTNO);
- r->value = 0;
-
- r = sanei_genesys_get_address(reg, 0x69);
- r->value = 0;
-
- r = sanei_genesys_get_address(reg, 0x6a);
- r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1);
-
- r = sanei_genesys_get_address(reg, 0x5f);
- r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1);
+ reg->set8(0x67, 0x3f);
+ reg->set8(0x68, 0x3f);
+ reg->set8(REG_STEPNO, 1);
+ reg->set8(REG_FASTNO, 1);
+ reg->set8(0x69, 1);
+ reg->set8(0x6a, fast_table.table.size() / step_multiplier);
+ reg->set8(0x5f, 1);
}
static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* reg,
+ const ScanSession& session,
+ Genesys_Register_Set* reg, const MotorProfile& motor_profile,
unsigned int scan_exposure_time,/*pixel*/
unsigned scan_yres, // dpi, motor resolution
- StepType scan_step_type,
unsigned int scan_lines,/*lines, scan resolution*/
unsigned int scan_dummy,
// number of scan lines to add in a scan_lines line
unsigned int feed_steps,/*1/base_ydpi*/
// maybe float for half/quarter step resolution?
- MotorFlag flags)
+ ScanFlag flags)
{
DBG_HELPER_ARGS(dbg, "scan_exposure_time=%d, scan_yres=%d, scan_step_type=%d, scan_lines=%d,"
" scan_dummy=%d, feed_steps=%d, flags=%x",
- scan_exposure_time, scan_yres, static_cast<unsigned>(scan_step_type),
+ scan_exposure_time, scan_yres, static_cast<unsigned>(motor_profile.step_type),
scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
- unsigned int fast_exposure;
+
+ unsigned step_multiplier = 2;
+
int use_fast_fed = 0;
unsigned int fast_time;
unsigned int slow_time;
unsigned int feedl;
- GenesysRegister* r;
unsigned int min_restep = 0x20;
- uint32_t z1, z2;
-
- fast_exposure = gl841_exposure_time(dev, sensor,
- dev->motor.base_ydpi / 4,
- StepType::FULL,
- 0,
- 0);
-
- DBG(DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure);
-
- {
- std::vector<uint16_t> table;
- table.resize(256, 0xffff);
-
- gl841_send_slope_table(dev, 0, table, 256);
- gl841_send_slope_table(dev, 1, table, 256);
- gl841_send_slope_table(dev, 2, table, 256);
- gl841_send_slope_table(dev, 3, table, 256);
- gl841_send_slope_table(dev, 4, table, 256);
- }
-
-
- /* motor frequency table */
- gl841_write_freq(dev, scan_yres);
/*
we calculate both tables for SCAN. the fast slope step count depends on
@@ -1022,30 +654,31 @@ static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor
allowed to use.
*/
- auto slow_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor,
- scan_step_type, scan_exposure_time,
- scan_yres);
+ // At least in LiDE 50, 60 the fast movement table is counted in full steps.
+ const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
+ if (fast_profile == nullptr) {
+ fast_profile = &motor_profile;
+ }
- auto back_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor,
- scan_step_type, 0, scan_yres);
+ auto slow_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres,
+ scan_exposure_time, step_multiplier, motor_profile);
- if (feed_steps < (slow_table.steps_count >> static_cast<unsigned>(scan_step_type))) {
+ if (feed_steps < (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type))) {
/*TODO: what should we do here?? go back to exposure calculation?*/
- feed_steps = slow_table.steps_count >> static_cast<unsigned>(scan_step_type);
+ feed_steps = slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type);
}
- auto fast_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor,
- StepType::FULL, fast_exposure,
- dev->motor.base_ydpi / 4);
+ auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
+ *fast_profile);
- unsigned max_fast_slope_steps_count = 1;
- if (feed_steps > (slow_table.steps_count >> static_cast<unsigned>(scan_step_type)) + 2) {
+ unsigned max_fast_slope_steps_count = step_multiplier;
+ if (feed_steps > (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)) + 2) {
max_fast_slope_steps_count = (feed_steps -
- (slow_table.steps_count >> static_cast<unsigned>(scan_step_type))) / 2;
+ (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type))) / 2;
}
- if (fast_table.steps_count > max_fast_slope_steps_count) {
- fast_table.slice_steps(max_fast_slope_steps_count);
+ if (fast_table.table.size() > max_fast_slope_steps_count) {
+ fast_table.slice_steps(max_fast_slope_steps_count, step_multiplier);
}
/* fast fed special cases handling */
@@ -1056,8 +689,8 @@ static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor
2-feed mode */
use_fast_fed = 0;
}
- else if (feed_steps < fast_table.steps_count * 2 +
- (slow_table.steps_count >> static_cast<unsigned>(scan_step_type)))
+ else if (feed_steps < fast_table.table.size() * 2 +
+ (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
{
use_fast_fed = 0;
DBG(DBG_info, "%s: feed too short, slow move forced.\n", __func__);
@@ -1071,113 +704,70 @@ static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor
/*NOTE: fast_exposure is per base_ydpi/4*/
/*we use full steps as base unit here*/
fast_time =
- fast_exposure / 4 *
- (feed_steps - fast_table.steps_count*2 -
- (slow_table.steps_count >> static_cast<unsigned>(scan_step_type)))
- + fast_table.pixeltime_sum*2 + slow_table.pixeltime_sum;
+ (fast_table.table.back() << static_cast<unsigned>(fast_profile->step_type)) / 4 *
+ (feed_steps - fast_table.table.size()*2 -
+ (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
+ + fast_table.pixeltime_sum() * 2 + slow_table.pixeltime_sum();
slow_time =
(scan_exposure_time * scan_yres) / dev->motor.base_ydpi *
- (feed_steps - (slow_table.steps_count >> static_cast<unsigned>(scan_step_type)))
- + slow_table.pixeltime_sum;
+ (feed_steps - (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
+ + slow_table.pixeltime_sum();
- DBG(DBG_info, "%s: Time for slow move: %d\n", __func__, slow_time);
- DBG(DBG_info, "%s: Time for fast move: %d\n", __func__, fast_time);
+ use_fast_fed = fast_time < slow_time;
+ }
- use_fast_fed = fast_time < slow_time;
+ if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
+ use_fast_fed = false;
}
if (use_fast_fed) {
- feedl = feed_steps - fast_table.steps_count * 2 -
- (slow_table.steps_count >> static_cast<unsigned>(scan_step_type));
- } else if ((feed_steps << static_cast<unsigned>(scan_step_type)) < slow_table.steps_count) {
+ feedl = feed_steps - fast_table.table.size() * 2 -
+ (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type));
+ } else if ((feed_steps << static_cast<unsigned>(motor_profile.step_type)) < slow_table.table.size()) {
feedl = 0;
} else {
- feedl = (feed_steps << static_cast<unsigned>(scan_step_type)) - slow_table.steps_count;
+ feedl = (feed_steps << static_cast<unsigned>(motor_profile.step_type)) - slow_table.table.size();
}
DBG(DBG_info, "%s: Decided to use %s mode\n", __func__, use_fast_fed?"fast feed":"slow feed");
-/* all needed slopes available. we did even decide which mode to use.
- what next?
- - transfer slopes
-SCAN:
-flags \ use_fast_fed ! 0 1
-------------------------\--------------------
- 0 ! 0,1,2 0,1,2,3
-MotorFlag::AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4
-OFF: none
-FEED: 3
-GO_HOME: 3
-HOME_FREE: 3
- - setup registers
- * slope specific registers (already done)
- * DECSEL for HOME_FREE/GO_HOME/SCAN
- * FEEDL
- * MTRREV
- * MTRPWR
- * FASTFED
- * STEPSEL
- * MTRPWM
- * FSTPSEL
- * FASTPWM
- * HOMENEG
- * BWDSTEP
- * FWDSTEP
- * Z1
- * Z2
- */
-
- r = sanei_genesys_get_address (reg, 0x3d);
- r->value = (feedl >> 16) & 0xf;
- r = sanei_genesys_get_address (reg, 0x3e);
- r->value = (feedl >> 8) & 0xff;
- r = sanei_genesys_get_address (reg, 0x3f);
- r->value = feedl & 0xff;
- r = sanei_genesys_get_address (reg, 0x5e);
- r->value &= ~0xe0;
-
- r = sanei_genesys_get_address (reg, 0x25);
- r->value = (scan_lines >> 16) & 0xf;
- r = sanei_genesys_get_address (reg, 0x26);
- r->value = (scan_lines >> 8) & 0xff;
- r = sanei_genesys_get_address (reg, 0x27);
- r->value = scan_lines & 0xff;
-
- r = sanei_genesys_get_address (reg, 0x02);
- r->value &= ~0x01; /*LONGCURV OFF*/
- r->value &= ~0x80; /*NOT_HOME OFF*/
- r->value |= 0x10;
-
- r->value &= ~0x06;
+ reg->set8(0x3d, (feedl >> 16) & 0xf);
+ reg->set8(0x3e, (feedl >> 8) & 0xff);
+ reg->set8(0x3f, feedl & 0xff);
+ reg->find_reg(0x5e).value &= ~0xe0;
+ reg->set8(0x25, (scan_lines >> 16) & 0xf);
+ reg->set8(0x26, (scan_lines >> 8) & 0xff);
+ reg->set8(0x27, scan_lines & 0xff);
+ reg->find_reg(0x02).value = REG_0x02_MTRPWR;
+
+ if (has_flag(flags, ScanFlag::REVERSE)) {
+ reg->find_reg(0x02).value |= REG_0x02_MTRREV;
+ } else {
+ reg->find_reg(0x02).value &= ~REG_0x02_MTRREV;
+ }
if (use_fast_fed)
- r->value |= 0x08;
+ reg->find_reg(0x02).value |= 0x08;
else
- r->value &= ~0x08;
+ reg->find_reg(0x02).value &= ~0x08;
- if (has_flag(flags, MotorFlag::AUTO_GO_HOME))
- r->value |= 0x20;
+ if (has_flag(flags, ScanFlag::AUTO_GO_HOME))
+ reg->find_reg(0x02).value |= 0x20;
else
- r->value &= ~0x20;
+ reg->find_reg(0x02).value &= ~0x20;
- if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE)) {
- r->value |= 0x40;
+ if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) {
+ reg->find_reg(0x02).value |= 0x40;
} else {
- r->value &= ~0x40;
+ reg->find_reg(0x02).value &= ~0x40;
}
- gl841_send_slope_table(dev, 0, slow_table.table, 256);
-
- gl841_send_slope_table(dev, 1, back_table.table, 256);
+ scanner_send_slope_table(dev, sensor, 0, slow_table.table);
+ scanner_send_slope_table(dev, sensor, 1, slow_table.table);
+ scanner_send_slope_table(dev, sensor, 2, slow_table.table);
+ scanner_send_slope_table(dev, sensor, 3, fast_table.table);
+ scanner_send_slope_table(dev, sensor, 4, fast_table.table);
- gl841_send_slope_table(dev, 2, slow_table.table, 256);
-
- if (use_fast_fed) {
- gl841_send_slope_table(dev, 3, fast_table.table, 256);
- }
-
- if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) {
- gl841_send_slope_table(dev, 4, fast_table.table, 256);
- }
+ gl841_write_freq(dev, scan_yres);
/* now reg 0x21 and 0x24 are available, we can calculate reg 0x22 and 0x23,
reg 0x60-0x62 and reg 0x63-0x65
@@ -1185,19 +775,18 @@ HOME_FREE: 3
2*STEPNO+FWDSTEP=2*FASTNO+BWDSTEP
*/
/* steps of table 0*/
- if (min_restep < slow_table.steps_count * 2 + 2) {
- min_restep = slow_table.steps_count * 2 + 2;
+ if (min_restep < slow_table.table.size() * 2 + 2) {
+ min_restep = slow_table.table.size() * 2 + 2;
}
/* steps of table 1*/
- if (min_restep < back_table.steps_count * 2 + 2) {
- min_restep = back_table.steps_count * 2 + 2;
+ if (min_restep < slow_table.table.size() * 2 + 2) {
+ min_restep = slow_table.table.size() * 2 + 2;
}
/* steps of table 0*/
- r = sanei_genesys_get_address(reg, REG_FWDSTEP);
- r->value = min_restep - slow_table.steps_count*2;
+ reg->set8(REG_FWDSTEP, min_restep - slow_table.table.size()*2);
+
/* steps of table 1*/
- r = sanei_genesys_get_address(reg, REG_BWDSTEP);
- r->value = min_restep - back_table.steps_count*2;
+ reg->set8(REG_BWDSTEP, min_restep - slow_table.table.size()*2);
/*
for z1/z2:
@@ -1214,64 +803,17 @@ HOME_FREE: 3
z1 = (slope_0_time-1) % exposure_time;
z2 = (slope_0_time-1) % exposure_time;
*/
- z1 = z2 = 0;
-
- DBG(DBG_info, "%s: z1 = %d\n", __func__, z1);
- DBG(DBG_info, "%s: z2 = %d\n", __func__, z2);
- r = sanei_genesys_get_address (reg, 0x60);
- r->value = ((z1 >> 16) & 0xff);
- r = sanei_genesys_get_address (reg, 0x61);
- r->value = ((z1 >> 8) & 0xff);
- r = sanei_genesys_get_address (reg, 0x62);
- r->value = (z1 & 0xff);
- r = sanei_genesys_get_address (reg, 0x63);
- r->value = ((z2 >> 16) & 0xff);
- r = sanei_genesys_get_address (reg, 0x64);
- r->value = ((z2 >> 8) & 0xff);
- r = sanei_genesys_get_address (reg, 0x65);
- r->value = (z2 & 0xff);
-
- r = sanei_genesys_get_address(reg, REG_0x1E);
- r->value &= REG_0x1E_WDTIME;
- r->value |= scan_dummy;
-
- r = sanei_genesys_get_address (reg, 0x67);
- r->value = 0x3f | (static_cast<unsigned>(scan_step_type) << 6);
-
- r = sanei_genesys_get_address (reg, 0x68);
- r->value = 0x3f;
-
- r = sanei_genesys_get_address(reg, REG_STEPNO);
- r->value = (slow_table.steps_count >> 1) + (slow_table.steps_count & 1);
-
- r = sanei_genesys_get_address(reg, REG_FASTNO);
- r->value = (back_table.steps_count >> 1) + (back_table.steps_count & 1);
-
- r = sanei_genesys_get_address (reg, 0x69);
- r->value = (slow_table.steps_count >> 1) + (slow_table.steps_count & 1);
-
- r = sanei_genesys_get_address (reg, 0x6a);
- r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1);
-
- r = sanei_genesys_get_address (reg, 0x5f);
- r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1);
-}
-
-static int
-gl841_get_dpihw(Genesys_Device * dev)
-{
- GenesysRegister* r;
- r = sanei_genesys_get_address(&dev->reg, 0x05);
- if ((r->value & REG_0x05_DPIHW) == REG_0x05_DPIHW_600) {
- return 600;
- }
- if ((r->value & REG_0x05_DPIHW) == REG_0x05_DPIHW_1200) {
- return 1200;
- }
- if ((r->value & REG_0x05_DPIHW) == REG_0x05_DPIHW_2400) {
- return 2400;
- }
- return 0;
+ reg->set24(REG_0x60, 0);
+ reg->set24(REG_0x63, 0);
+ reg->find_reg(REG_0x1E).value &= REG_0x1E_WDTIME;
+ reg->find_reg(REG_0x1E).value |= scan_dummy;
+ reg->set8(0x67, 0x3f | (static_cast<unsigned>(motor_profile.step_type) << 6));
+ reg->set8(0x68, 0x3f | (static_cast<unsigned>(fast_profile->step_type) << 6));
+ reg->set8(REG_STEPNO, slow_table.table.size() / step_multiplier);
+ reg->set8(REG_FASTNO, slow_table.table.size() / step_multiplier);
+ reg->set8(0x69, slow_table.table.size() / step_multiplier);
+ reg->set8(0x6a, fast_table.table.size() / step_multiplier);
+ reg->set8(0x5f, fast_table.table.size() / step_multiplier);
}
static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
@@ -1279,108 +821,99 @@ static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
const ScanSession& session)
{
DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time);
- GenesysRegister* r;
uint16_t expavg, expr, expb, expg;
dev->cmd_set->set_fe(dev, sensor, AFE_SET);
/* gpio part.*/
if (dev->model->gpio_id == GpioId::CANON_LIDE_35) {
- r = sanei_genesys_get_address(reg, REG_0x6C);
- if (session.ccd_size_divisor > 1) {
- r->value &= ~0x80;
+ if (session.params.xres <= 600) {
+ reg->find_reg(REG_0x6C).value &= ~0x80;
} else {
- r->value |= 0x80;
+ reg->find_reg(REG_0x6C).value |= 0x80;
}
}
if (dev->model->gpio_id == GpioId::CANON_LIDE_80) {
- r = sanei_genesys_get_address(reg, REG_0x6C);
- if (session.ccd_size_divisor > 1) {
- r->value &= ~0x40;
- r->value |= 0x20;
+ if (session.params.xres <= 600) {
+ reg->find_reg(REG_0x6C).value &= ~0x40;
+ reg->find_reg(REG_0x6C).value |= 0x20;
} else {
- r->value &= ~0x20;
- r->value |= 0x40;
+ reg->find_reg(REG_0x6C).value &= ~0x20;
+ reg->find_reg(REG_0x6C).value |= 0x40;
}
- }
+ }
/* enable shading */
- r = sanei_genesys_get_address (reg, 0x01);
- r->value |= REG_0x01_SCAN;
+ reg->find_reg(0x01).value |= REG_0x01_SCAN;
if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
- (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) {
- r->value &= ~REG_0x01_DVDSET;
+ has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION)) {
+ reg->find_reg(0x01).value &= ~REG_0x01_DVDSET;
} else {
- r->value |= REG_0x01_DVDSET;
+ reg->find_reg(0x01).value |= REG_0x01_DVDSET;
}
/* average looks better than deletion, and we are already set up to
use one of the average enabled resolutions
*/
- r = sanei_genesys_get_address (reg, 0x03);
- r->value |= REG_0x03_AVEENB;
+ reg->find_reg(0x03).value |= REG_0x03_AVEENB;
sanei_genesys_set_lamp_power(dev, sensor, *reg,
!has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
/* BW threshold */
- r = sanei_genesys_get_address (reg, 0x2e);
- r->value = dev->settings.threshold;
- r = sanei_genesys_get_address (reg, 0x2f);
- r->value = dev->settings.threshold;
+ reg->set8(0x2e, 0x7f);
+ reg->set8(0x2f, 0x7f);
/* monochrome / color scan */
- r = sanei_genesys_get_address (reg, 0x04);
switch (session.params.depth) {
case 8:
- r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
+ reg->find_reg(0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
break;
case 16:
- r->value &= ~REG_0x04_LINEART;
- r->value |= REG_0x04_BITSET;
+ reg->find_reg(0x04).value &= ~REG_0x04_LINEART;
+ reg->find_reg(0x04).value |= REG_0x04_BITSET;
break;
}
/* AFEMOD should depend on FESET, and we should set these
* bits separately */
- r->value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
+ reg->find_reg(0x04).value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) {
- r->value |= 0x10; /* no filter */
+ reg->find_reg(0x04).value |= 0x10; /* no filter */
}
else if (session.params.channels == 1)
{
switch (session.params.color_filter)
{
case ColorFilter::RED:
- r->value |= 0x14;
+ reg->find_reg(0x04).value |= 0x14;
break;
case ColorFilter::GREEN:
- r->value |= 0x18;
+ reg->find_reg(0x04).value |= 0x18;
break;
case ColorFilter::BLUE:
- r->value |= 0x1c;
+ reg->find_reg(0x04).value |= 0x1c;
break;
default:
- r->value |= 0x10;
+ reg->find_reg(0x04).value |= 0x10;
break;
}
}
else
{
if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) {
- r->value |= 0x22; /* slow color pixel by pixel */
+ reg->find_reg(0x04).value |= 0x22; /* slow color pixel by pixel */
}
else
{
- r->value |= 0x10; /* color pixel by pixel */
+ reg->find_reg(0x04).value |= 0x10; /* color pixel by pixel */
}
}
/* CIS scanners can do true gray by setting LEDADD */
- r = sanei_genesys_get_address (reg, 0x87);
- r->value &= ~REG_0x87_LEDADD;
+ reg->find_reg(0x87).value &= ~REG_0x87_LEDADD;
if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) {
- r->value |= REG_0x87_LEDADD;
+ reg->find_reg(0x87).value |= REG_0x87_LEDADD;
expr = reg->get16(REG_EXPR);
expg = reg->get16(REG_EXPG);
expb = reg->get16(REG_EXPB);
@@ -1405,21 +938,14 @@ static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
}
/* sensor parameters */
- sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 1, session.ccd_size_divisor);
-
- r = sanei_genesys_get_address (reg, 0x29);
- r->value = 255; /*<<<"magic" number, only suitable for cis*/
-
- reg->set16(REG_DPISET, gl841_get_dpihw(dev) * session.output_resolution / session.optical_resolution);
+ scanner_setup_sensor(*dev, sensor, dev->reg);
+ reg->set8(0x29, 255); /*<<<"magic" number, only suitable for cis*/
+ reg->set16(REG_DPISET, sensor.register_dpiset);
reg->set16(REG_STRPIXEL, session.pixel_startx);
reg->set16(REG_ENDPIXEL, session.pixel_endx);
-
reg->set24(REG_MAXWD, session.output_line_bytes);
-
reg->set16(REG_LPERIOD, exposure_time);
-
- r = sanei_genesys_get_address (reg, 0x34);
- r->value = sensor.dummy_pixel;
+ reg->set8(0x34, sensor.dummy_pixel);
}
static int
@@ -1446,56 +972,17 @@ gl841_get_led_exposure(Genesys_Device * dev, const Genesys_Sensor& sensor)
/** @brief compute exposure time
* Compute exposure time for the device and the given scan resolution
*/
-static int
-gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor,
- float slope_dpi,
- StepType scan_step_type,
- int start,
- int used_pixels)
+static int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor,
+ const MotorProfile& profile, float slope_dpi,
+ int start,
+ int used_pixels)
{
-int exposure_time = 0;
int led_exposure;
led_exposure=gl841_get_led_exposure(dev, sensor);
- exposure_time = sanei_genesys_exposure_time2(
- dev,
- slope_dpi,
- scan_step_type,
- start+used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/
- led_exposure);
-
- return exposure_time;
-}
-
-/**@brief compute scan_step_type
- * Try to do at least 4 steps per line. if that is impossible we will have to
- * live with that.
- * @param dev device
- * @param yres motor resolution
- */
-static StepType gl841_scan_step_type(Genesys_Device *dev, int yres)
-{
- StepType type = StepType::FULL;
-
- /* TODO : check if there is a bug around the use of max_step_type */
- /* should be <=1, need to chek all devices entry in genesys_devices */
- if (yres * 4 < dev->motor.base_ydpi || dev->motor.max_step_type() == StepType::FULL) {
- type = StepType::FULL;
- } else if (yres * 4 < dev->motor.base_ydpi * 2 ||
- dev->motor.max_step_type() <= StepType::HALF)
- {
- type = StepType::HALF;
- } else {
- type = StepType::QUARTER;
- }
-
- /* this motor behaves differently */
- if (dev->model->motor_id==MotorId::CANON_LIDE_80) {
- // driven by 'frequency' tables ?
- type = StepType::FULL;
- }
-
- return type;
+ return sanei_genesys_exposure_time2(dev, profile, slope_dpi,
+ start + used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/
+ led_exposure);
}
void CommandSetGl841::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
@@ -1511,34 +998,6 @@ void CommandSetGl841::init_regs_for_scan_session(Genesys_Device* dev, const Gene
int slope_dpi = 0;
int dummy = 0;
-/*
-results:
-
-for scanner:
-start
-end
-dpiset
-exposure_time
-dummy
-z1
-z2
-
-for ordered_read:
- dev->words_per_line
- dev->read_factor
- dev->requested_buffer_size
- dev->read_buffer_size
- dev->read_pos
- dev->read_bytes_in_buffer
- dev->read_bytes_left
- dev->max_shift
- dev->stagger
-
-independent of our calculated values:
- dev->total_bytes_read
- dev->bytes_to_read
- */
-
/* dummy */
/* dummy lines: may not be usefull, for instance 250 dpi works with 0 or 1
dummy line. Maybe the dummy line adds correctness since the motor runs
@@ -1577,48 +1036,34 @@ dummy \ scanned lines
slope_dpi = slope_dpi * (1 + dummy);
- StepType scan_step_type = gl841_scan_step_type(dev, session.params.yres);
- exposure_time = gl841_exposure_time(dev, sensor,
- slope_dpi,
- scan_step_type,
- session.pixel_startx,
- session.optical_pixels);
- DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time);
+ const auto& motor_profile = get_motor_profile(dev->motor.profiles, 0, session);
+
+ exposure_time = gl841_exposure_time(dev, sensor, motor_profile, slope_dpi,
+ session.pixel_startx, session.optical_pixels);
gl841_init_optical_regs_scan(dev, sensor, reg, exposure_time, session);
move = session.params.starty;
- DBG(DBG_info, "%s: move=%d steps\n", __func__, move);
/* subtract current head position */
move -= (dev->head_pos(ScanHeadId::PRIMARY) * session.params.yres) / dev->motor.base_ydpi;
- DBG(DBG_info, "%s: move=%d steps\n", __func__, move);
if (move < 0)
move = 0;
/* round it */
/* the move is not affected by dummy -- pierre */
-/* move = ((move + dummy) / (dummy + 1)) * (dummy + 1);
- DBG(DBG_info, "%s: move=%d steps\n", __func__, move);*/
+/* move = ((move + dummy) / (dummy + 1)) * (dummy + 1);*/
if (has_flag(session.params.flags, ScanFlag::SINGLE_LINE)) {
- gl841_init_motor_regs_off(reg, dev->model->is_cis ? session.output_line_count * session.params.channels
- : session.output_line_count);
+ gl841_init_motor_regs_off(reg, session.optical_line_count);
} else {
- auto motor_flag = has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) ?
- MotorFlag::DISABLE_BUFFER_FULL_MOVE : MotorFlag::NONE;
-
- gl841_init_motor_regs_scan(dev, sensor, reg, exposure_time, slope_dpi, scan_step_type,
- dev->model->is_cis ? session.output_line_count * session.params.channels
- : session.output_line_count,
- dummy, move, motor_flag);
+ gl841_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure_time,
+ slope_dpi, session.optical_line_count, dummy, move,
+ session.params.flags);
}
- dev->read_buffer.clear();
- dev->read_buffer.alloc(session.buffer_size_read);
-
- build_image_pipeline(dev, session);
+ setup_image_pipeline(*dev, session);
dev->read_active = true;
@@ -1634,32 +1079,62 @@ ScanSession CommandSetGl841::calculate_scan_session(const Genesys_Device* dev,
const Genesys_Sensor& sensor,
const Genesys_Settings& settings) const
{
- int start;
-
- DBG(DBG_info, "%s ", __func__);
+ DBG_HELPER(dbg);
debug_dump(DBG_info, settings);
-/* start */
- start = static_cast<int>(dev->model->x_offset);
- start += static_cast<int>(settings.tl_x);
+ /* steps to move to reach scanning area:
+ - first we move to physical start of scanning
+ either by a fixed steps amount from the black strip
+ or by a fixed amount from parking position,
+ minus the steps done during shading calibration
+ - then we move by the needed offset whitin physical
+ scanning area
+
+ assumption: steps are expressed at maximum motor resolution
+
+ we need:
+ float y_offset;
+ float y_size;
+ float y_offset_calib;
+ mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH
+ */
+ float move = dev->model->y_offset;
+ move += dev->settings.tl_y;
- start = static_cast<int>((start * sensor.optical_res) / MM_PER_INCH);
+ int move_dpi = dev->motor.base_ydpi;
+ move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
- ScanSession session;
- session.params.xres = settings.xres;
- session.params.yres = settings.yres;
- session.params.startx = start;
- session.params.starty = 0; // not used
- session.params.pixels = settings.pixels;
- session.params.requested_pixels = settings.requested_pixels;
- session.params.lines = settings.lines;
- session.params.depth = settings.depth;
- session.params.channels = settings.get_channels();
- session.params.scan_method = settings.scan_method;
- session.params.scan_mode = settings.scan_mode;
- session.params.color_filter = settings.color_filter;
- session.params.flags = ScanFlag::NONE;
+ float start = dev->model->x_offset;
+ start += dev->settings.tl_x;
+ start = static_cast<float>((start * dev->settings.xres) / MM_PER_INCH);
+ // we enable true gray for cis scanners only, and just when doing
+ // scan since color calibration is OK for this mode
+ ScanFlag flags = ScanFlag::NONE;
+
+ // true gray (led add for cis scanners)
+ if (dev->model->is_cis && dev->settings.true_gray &&
+ dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS &&
+ dev->model->sensor_id != SensorId::CIS_CANON_LIDE_80)
+ {
+ // on Lide 80 the LEDADD bit results in only red LED array being lit
+ flags |= ScanFlag::ENABLE_LEDADD;
+ }
+
+ ScanSession session;
+ session.params.xres = dev->settings.xres;
+ session.params.yres = dev->settings.yres;
+ session.params.startx = static_cast<unsigned>(start);
+ session.params.starty = static_cast<unsigned>(move);
+ session.params.pixels = dev->settings.pixels;
+ session.params.requested_pixels = dev->settings.requested_pixels;
+ session.params.lines = dev->settings.lines;
+ session.params.depth = dev->settings.depth;
+ session.params.channels = dev->settings.get_channels();
+ session.params.scan_method = dev->settings.scan_method;
+ session.params.scan_mode = dev->settings.scan_mode;
+ session.params.color_filter = dev->settings.color_filter;
+ session.params.flags = flags;
compute_session(dev, session, sensor);
return session;
@@ -1709,7 +1184,7 @@ void CommandSetGl841::save_power(Genesys_Device* dev, bool enable) const
uint8_t val = dev->interface->read_register(REG_0x6B);
dev->interface->write_register(REG_0x6B, val & ~REG_0x6B_GPO17);
dev->reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17;
- dev->calib_reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17;
+ dev->initial_regs.find_reg(0x6b).value &= ~REG_0x6B_GPO17;
}
set_fe(dev, sensor, AFE_POWER_SAVE);
@@ -1741,13 +1216,13 @@ void CommandSetGl841::save_power(Genesys_Device* dev, bool enable) const
val = dev->interface->read_register(REG_0x6B);
dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO17);
dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17;
- dev->calib_reg.find_reg(0x6b).value |= REG_0x6B_GPO17;
+ dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO17;
/*enable GPO18*/
val = dev->interface->read_register(REG_0x6B);
dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO18);
dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO18;
- dev->calib_reg.find_reg(0x6b).value |= REG_0x6B_GPO18;
+ dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO18;
}
if (dev->model->gpio_id == GpioId::DP665
@@ -1756,7 +1231,7 @@ void CommandSetGl841::save_power(Genesys_Device* dev, bool enable) const
uint8_t val = dev->interface->read_register(REG_0x6B);
dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO17);
dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17;
- dev->calib_reg.find_reg(0x6b).value |= REG_0x6B_GPO17;
+ dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO17;
}
}
@@ -1826,47 +1301,6 @@ void CommandSetGl841::set_powersaving(Genesys_Device* dev, int delay /* in minut
dev->interface->write_registers(local_reg);
}
-static void gl841_stop_action(Genesys_Device* dev)
-{
- DBG_HELPER(dbg);
- Genesys_Register_Set local_reg;
- unsigned int loop;
-
- scanner_read_print_status(*dev);
-
- if (scanner_is_motor_stopped(*dev)) {
- DBG(DBG_info, "%s: already stopped\n", __func__);
- return;
- }
-
- local_reg = dev->reg;
-
- regs_set_optical_off(dev->model->asic_type, local_reg);
-
- gl841_init_motor_regs_off(&local_reg,0);
- dev->interface->write_registers(local_reg);
-
- if (is_testing_mode()) {
- return;
- }
-
- /* looks like writing the right registers to zero is enough to get the chip
- out of scan mode into command mode, actually triggering(writing to
- register 0x0f) seems to be unnecessary */
-
- loop = 10;
- while (loop > 0) {
- if (scanner_is_motor_stopped(*dev)) {
- return;
- }
-
- dev->interface->sleep_ms(100);
- loop--;
- }
-
- throw SaneException(SANE_STATUS_IO_ERROR, "could not stop motor");
-}
-
static bool gl841_get_paper_sensor(Genesys_Device* dev)
{
DBG_HELPER(dbg);
@@ -1886,7 +1320,6 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const
if (!dev->model->is_sheetfed) {
DBG(DBG_proc, "%s: there is no \"eject sheet\"-concept for non sheet fed\n", __func__);
- DBG(DBG_proc, "%s: finished\n", __func__);
return;
}
@@ -1895,22 +1328,21 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const
// FIXME: unused result
scanner_read_status(*dev);
-
- gl841_stop_action(dev);
+ scanner_stop_action(*dev);
local_reg = dev->reg;
regs_set_optical_off(dev->model->asic_type, local_reg);
const auto& sensor = sanei_genesys_find_sensor_any(dev);
- gl841_init_motor_regs(dev, sensor, &local_reg, 65536, MOTOR_ACTION_FEED, MotorFlag::NONE);
+ gl841_init_motor_regs_feed(dev, sensor, &local_reg, 65536, ScanFlag::NONE);
dev->interface->write_registers(local_reg);
try {
scanner_start_action(*dev, true);
} catch (...) {
- catch_all_exceptions(__func__, [&]() { gl841_stop_action(dev); });
+ catch_all_exceptions(__func__, [&]() { scanner_stop_action(*dev); });
// restore original registers
catch_all_exceptions(__func__, [&]()
{
@@ -1921,7 +1353,7 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const
if (is_testing_mode()) {
dev->interface->test_checkpoint("eject_document");
- gl841_stop_action(dev);
+ scanner_stop_action(*dev);
return;
}
@@ -1936,10 +1368,9 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const
{
if (!gl841_get_paper_sensor(dev)) {
- DBG(DBG_info, "%s: reached home position\n", __func__);
- DBG(DBG_proc, "%s: finished\n", __func__);
- break;
- }
+ DBG(DBG_info, "%s: reached home position\n", __func__);
+ break;
+ }
dev->interface->sleep_ms(100);
--loop;
}
@@ -1948,16 +1379,15 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const
{
// when we come here then the scanner needed too much time for this, so we better stop
// the motor
- catch_all_exceptions(__func__, [&](){ gl841_stop_action(dev); });
+ catch_all_exceptions(__func__, [&](){ scanner_stop_action(*dev); });
throw SaneException(SANE_STATUS_IO_ERROR,
"timeout while waiting for scanhead to go home");
}
}
- feed_mm = static_cast<float>(dev->model->eject_feed);
- if (dev->document)
- {
- feed_mm += static_cast<float>(dev->model->post_scan);
+ feed_mm = dev->model->eject_feed;
+ if (dev->document) {
+ feed_mm += dev->model->post_scan;
}
sanei_genesys_read_feed_steps(dev, &init_steps);
@@ -1981,11 +1411,22 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const
++loop;
}
- gl841_stop_action(dev);
+ scanner_stop_action(*dev);
dev->document = false;
}
+void CommandSetGl841::update_home_sensor_gpio(Genesys_Device& dev) const
+{
+ if (dev.model->gpio_id == GpioId::CANON_LIDE_35) {
+ dev.interface->read_register(REG_0x6C);
+ dev.interface->write_register(REG_0x6C, dev.gpo.regs.get_value(0x6c));
+ }
+ if (dev.model->gpio_id == GpioId::CANON_LIDE_80) {
+ dev.interface->read_register(REG_0x6B);
+ dev.interface->write_register(REG_0x6B, REG_0x6B_GPO18 | REG_0x6B_GPO17);
+ }
+}
void CommandSetGl841::load_document(Genesys_Device* dev) const
{
@@ -2064,8 +1505,6 @@ void CommandSetGl841::detect_document_end(Genesys_Device* dev) const
auto skip_lines = scan_end_lines - output_lines;
if (remaining_lines > skip_lines) {
- DBG(DBG_io, "%s: skip_lines=%zu\n", __func__, skip_lines);
-
remaining_lines -= skip_lines;
dev->get_pipeline_source().set_remaining_bytes(remaining_lines *
dev->session.output_line_bytes_raw);
@@ -2092,6 +1531,21 @@ void CommandSetGl841::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens
dev->interface->write_register(REG_0x6B, val);
}
+ if (dev->model->model_id == ModelId::CANON_LIDE_50 ||
+ dev->model->model_id == ModelId::CANON_LIDE_60)
+ {
+ if (dev->session.params.yres >= 1200) {
+ dev->interface->write_register(REG_0x6C, 0x82);
+ } else {
+ dev->interface->write_register(REG_0x6C, 0x02);
+ }
+ if (dev->session.params.yres >= 600) {
+ dev->interface->write_register(REG_0x6B, 0x01);
+ } else {
+ dev->interface->write_register(REG_0x6B, 0x03);
+ }
+ }
+
if (dev->model->sensor_id != SensorId::CCD_PLUSTEK_OPTICPRO_3600) {
local_reg.init_reg(0x03, reg->get8(0x03) | REG_0x03_LAMPPWR);
} else {
@@ -2123,439 +1577,53 @@ void CommandSetGl841::end_scan(Genesys_Device* dev, Genesys_Register_Set __sane_
DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop);
if (!dev->model->is_sheetfed) {
- gl841_stop_action(dev);
+ scanner_stop_action(*dev);
}
}
-// Moves the slider to steps
-static void gl841_feed(Genesys_Device* dev, int steps)
-{
- DBG_HELPER_ARGS(dbg, "steps = %d", steps);
- Genesys_Register_Set local_reg;
- int loop;
-
- gl841_stop_action(dev);
-
- // FIXME: we should pick sensor according to the resolution scanner is currently operating on
- const auto& sensor = sanei_genesys_find_sensor_any(dev);
-
- local_reg = dev->reg;
-
- regs_set_optical_off(dev->model->asic_type, local_reg);
-
- gl841_init_motor_regs(dev, sensor, &local_reg, steps, MOTOR_ACTION_FEED, MotorFlag::NONE);
-
- dev->interface->write_registers(local_reg);
-
- try {
- scanner_start_action(*dev, true);
- } catch (...) {
- catch_all_exceptions(__func__, [&]() { gl841_stop_action (dev); });
- // restore original registers
- catch_all_exceptions(__func__, [&]()
- {
- dev->interface->write_registers(dev->reg);
- });
- throw;
- }
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("feed");
- dev->advance_head_pos_by_steps(ScanHeadId::PRIMARY, Direction::FORWARD, steps);
- gl841_stop_action(dev);
- return;
- }
-
- loop = 0;
- while (loop < 300) /* do not wait longer then 30 seconds */
- {
- auto status = scanner_read_status(*dev);
-
- if (!status.is_motor_enabled) {
- DBG(DBG_proc, "%s: finished\n", __func__);
- dev->advance_head_pos_by_steps(ScanHeadId::PRIMARY, Direction::FORWARD, steps);
- return;
- }
- dev->interface->sleep_ms(100);
- ++loop;
- }
-
- /* when we come here then the scanner needed too much time for this, so we better stop the motor */
- gl841_stop_action (dev);
-
- dev->set_head_pos_unknown();
-
- throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home");
-}
-
// Moves the slider to the home (top) position slowly
void CommandSetGl841::move_back_home(Genesys_Device* dev, bool wait_until_home) const
{
- DBG_HELPER_ARGS(dbg, "wait_until_home = %d", wait_until_home);
- Genesys_Register_Set local_reg;
- int loop = 0;
-
- if (dev->model->is_sheetfed) {
- DBG(DBG_proc, "%s: there is no \"home\"-concept for sheet fed\n", __func__);
- DBG(DBG_proc, "%s: finished\n", __func__);
- return;
- }
-
- // reset gpio pin
- uint8_t val;
- if (dev->model->gpio_id == GpioId::CANON_LIDE_35) {
- val = dev->interface->read_register(REG_0x6C);
- val = dev->gpo.regs.get_value(0x6c);
- dev->interface->write_register(REG_0x6C, val);
- }
- if (dev->model->gpio_id == GpioId::CANON_LIDE_80) {
- val = dev->interface->read_register(REG_0x6B);
- val = REG_0x6B_GPO18 | REG_0x6B_GPO17;
- dev->interface->write_register(REG_0x6B, val);
- }
- dev->cmd_set->save_power(dev, false);
-
- // first read gives HOME_SENSOR true
- auto status = scanner_read_reliable_status(*dev);
-
-
- if (status.is_at_home) {
- DBG(DBG_info, "%s: already at home, completed\n", __func__);
- dev->set_head_pos_zero(ScanHeadId::PRIMARY);
- return;
- }
-
- scanner_stop_action_no_move(*dev, dev->reg);
-
- /* if motor is on, stop current action */
- if (status.is_motor_enabled) {
- gl841_stop_action(dev);
- }
-
- local_reg = dev->reg;
-
- const auto& sensor = sanei_genesys_find_sensor_any(dev);
-
- gl841_init_motor_regs(dev, sensor, &local_reg, 65536, MOTOR_ACTION_GO_HOME, MotorFlag::REVERSE);
-
- // set up for no scan
- regs_set_optical_off(dev->model->asic_type, local_reg);
-
- dev->interface->write_registers(local_reg);
-
- try {
- scanner_start_action(*dev, true);
- } catch (...) {
- catch_all_exceptions(__func__, [&]() { gl841_stop_action(dev); });
- // restore original registers
- catch_all_exceptions(__func__, [&]()
- {
- dev->interface->write_registers(dev->reg);
- });
- throw;
- }
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("move_back_home");
- dev->set_head_pos_zero(ScanHeadId::PRIMARY);
- return;
- }
-
- if (wait_until_home)
- {
- while (loop < 300) /* do not wait longer then 30 seconds */
- {
- auto status = scanner_read_status(*dev);
- if (status.is_at_home) {
- DBG(DBG_info, "%s: reached home position\n", __func__);
- DBG(DBG_proc, "%s: finished\n", __func__);
- dev->set_head_pos_zero(ScanHeadId::PRIMARY);
- return;
- }
- dev->interface->sleep_ms(100);
- ++loop;
- }
-
- // when we come here then the scanner needed too much time for this, so we better stop
- // the motor
- catch_all_exceptions(__func__, [&](){ gl841_stop_action(dev); });
- dev->set_head_pos_unknown();
- throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home");
- }
-
- DBG(DBG_info, "%s: scanhead is still moving\n", __func__);
-}
-
-// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi
-// from very top of scanner
-void CommandSetGl841::search_start_position(Genesys_Device* dev) const
-{
- DBG_HELPER(dbg);
- int size;
- Genesys_Register_Set local_reg;
-
- int pixels = 600;
- int dpi = 300;
-
- local_reg = dev->reg;
-
- /* sets for a 200 lines * 600 pixels */
- /* normal scan with no shading */
-
- // FIXME: the current approach of doing search only for one resolution does not work on scanners
- // whith employ different sensors with potentially different settings.
- const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method);
-
- ScanSession session;
- session.params.xres = dpi;
- session.params.yres = dpi;
- session.params.startx = 0;
- session.params.starty = 0; /*we should give a small offset here~60 steps*/
- session.params.pixels = 600;
- session.params.lines = dev->model->search_lines;
- session.params.depth = 8;
- session.params.channels = 1;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::GRAY;
- session.params.color_filter = ColorFilter::GREEN;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::IGNORE_LINE_DISTANCE |
- ScanFlag::DISABLE_BUFFER_FULL_MOVE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &local_reg, session);
-
- // send to scanner
- dev->interface->write_registers(local_reg);
-
- size = pixels * dev->model->search_lines;
-
- std::vector<uint8_t> data(size);
-
- dev->cmd_set->begin_scan(dev, sensor, &local_reg, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("search_start_position");
- dev->cmd_set->end_scan(dev, &local_reg, true);
- dev->reg = local_reg;
- return;
- }
-
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- sanei_genesys_read_data_from_scanner(dev, data.data(), size);
-
- if (DBG_LEVEL >= DBG_data) {
- sanei_genesys_write_pnm_file("gl841_search_position.pnm", data.data(), 8, 1, pixels,
- dev->model->search_lines);
- }
-
- dev->cmd_set->end_scan(dev, &local_reg, true);
-
- /* update regs to copy ASIC internal state */
- dev->reg = local_reg;
-
- for (auto& sensor_update :
- sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method))
- {
- sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels,
- dev->model->search_lines);
- }
+ scanner_move_back_home(*dev, wait_until_home);
}
-// sets up register for coarse gain calibration
-// todo: check it for scanners using it
-void CommandSetGl841::init_regs_for_coarse_calibration(Genesys_Device* dev,
- const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs) const
-{
- DBG_HELPER(dbg);
-
- ScanSession session;
- session.params.xres = dev->settings.xres;
- session.params.yres = dev->settings.yres;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel();
- session.params.lines = 20;
- session.params.depth = 16;
- session.params.channels = dev->settings.get_channels();
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = dev->settings.scan_mode;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &regs, session);
-
- DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__,
- sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres);
-
- dev->interface->write_registers(regs);
-
-/* if (DBG_LEVEL >= DBG_info)
- sanei_gl841_print_registers (regs);*/
-}
-
-
// init registers for shading calibration
void CommandSetGl841::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
- DBG_HELPER_ARGS(dbg, "lines = %zu", dev->calib_lines);
- SANE_Int ydpi;
- unsigned starty = 0;
-
- /* initial calibration reg values */
- regs = dev->reg;
-
- ydpi = dev->motor.base_ydpi;
- if (dev->model->motor_id == MotorId::PLUSTEK_OPTICPRO_3600) /* TODO PLUSTEK_3600: 1200dpi not yet working, produces dark bar */
- {
- ydpi = 600;
- }
- if (dev->model->motor_id == MotorId::CANON_LIDE_80) {
- ydpi = gl841_get_dpihw(dev);
- /* get over extra dark area for this model.
- It looks like different devices have dark areas of different width
- due to manufacturing variability. The initial value of starty was 140,
- but it moves the sensor almost past the dark area completely in places
- on certain devices.
-
- On a particular device the black area starts at roughly position
- 160 to 230 depending on location (the dark area is not completely
- parallel to the frame).
- */
- starty = 70;
- }
-
- dev->calib_channels = 3;
- dev->calib_lines = dev->model->shading_lines;
+ DBG_HELPER(dbg);
- unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres);
- unsigned factor = sensor.optical_res / resolution;
+ unsigned channels = 3;
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, dev->calib_channels,
+ unsigned resolution = sensor.shading_resolution;
+ const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
- dev->calib_pixels = calib_sensor.sensor_pixels / factor;
-
+ unsigned calib_lines =
+ static_cast<unsigned>(dev->model->y_size_calib_dark_white_mm * resolution / MM_PER_INCH);
+ unsigned starty =
+ static_cast<unsigned>(dev->model->y_offset_calib_dark_white_mm * dev->motor.base_ydpi / MM_PER_INCH);
ScanSession session;
session.params.xres = resolution;
- session.params.yres = ydpi;
+ session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = starty;
- session.params.pixels = dev->calib_pixels;
- session.params.lines = dev->calib_lines;
+ session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
+ session.params.lines = calib_lines;
session.params.depth = 16;
- session.params.channels = dev->calib_channels;
+ session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- /*ScanFlag::DISABLE_BUFFER_FULL_MOVE |*/
- ScanFlag::IGNORE_LINE_DISTANCE;
+ ScanFlag::DISABLE_GAMMA;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
- dev->interface->write_registers(regs);
+ dev->calib_session = session;
}
-// set up registers for the actual scan
-void CommandSetGl841::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const
-{
- DBG_HELPER(dbg);
- float move;
- int move_dpi;
- float start;
-
- debug_dump(DBG_info, dev->settings);
-
- /* steps to move to reach scanning area:
- - first we move to physical start of scanning
- either by a fixed steps amount from the black strip
- or by a fixed amount from parking position,
- minus the steps done during shading calibration
- - then we move by the needed offset whitin physical
- scanning area
-
- assumption: steps are expressed at maximum motor resolution
-
- we need:
- float y_offset;
- float y_size;
- float y_offset_calib;
- mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */
-
- /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is
- relative from origin, else, it is from parking position */
-
- move_dpi = dev->motor.base_ydpi;
-
- move = 0;
- if (dev->model->flags & GENESYS_FLAG_SEARCH_START) {
- move += static_cast<float>(dev->model->y_offset_calib_white);
- }
-
- DBG(DBG_info, "%s move=%f steps\n", __func__, move);
-
- move += static_cast<float>(dev->model->y_offset);
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
-
- move += static_cast<float>(dev->settings.tl_y);
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
-
- move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
-
-/* start */
- start = static_cast<float>(dev->model->x_offset);
-
- start += static_cast<float>(dev->settings.tl_x);
-
- start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
-
- /* we enable true gray for cis scanners only, and just when doing
- * scan since color calibration is OK for this mode
- */
- ScanFlag flags = ScanFlag::NONE;
-
- /* true gray (led add for cis scanners) */
- if(dev->model->is_cis && dev->settings.true_gray
- && dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS
- && dev->model->sensor_id != SensorId::CIS_CANON_LIDE_80)
- {
- // on Lide 80 the LEDADD bit results in only red LED array being lit
- DBG(DBG_io, "%s: activating LEDADD\n", __func__);
- flags |= ScanFlag::ENABLE_LEDADD;
- }
-
- ScanSession session;
- session.params.xres = dev->settings.xres;
- session.params.yres = dev->settings.yres;
- session.params.startx = static_cast<unsigned>(start);
- session.params.starty = static_cast<unsigned>(move);
- session.params.pixels = dev->settings.pixels;
- session.params.requested_pixels = dev->settings.requested_pixels;
- session.params.lines = dev->settings.lines;
- session.params.depth = dev->settings.depth;
- session.params.channels = dev->settings.get_channels();
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = dev->settings.scan_mode;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = flags;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &dev->reg, session);
-}
-
-
// this function sends generic gamma table (ie linear ones) or the Sensor specific one if provided
void CommandSetGl841::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const
{
@@ -2581,216 +1649,7 @@ void CommandSetGl841::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor
SensorExposure CommandSetGl841::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
- DBG_HELPER(dbg);
- int num_pixels;
- int total_size;
- int i, j;
- int val;
- int channels;
- int avg[3], avga, avge;
- int turn;
- uint16_t exp[3], target;
- int move;
-
- /* these 2 boundaries should be per sensor */
- uint16_t min_exposure=500;
- uint16_t max_exposure;
-
- /* feed to white strip if needed */
- if (dev->model->y_offset_calib_white > 0) {
- move = static_cast<int>(dev->model->y_offset_calib_white);
- move = static_cast<int>((move * (dev->motor.base_ydpi)) / MM_PER_INCH);
- DBG(DBG_io, "%s: move=%d lines\n", __func__, move);
- gl841_feed(dev, move);
- }
-
- /* offset calibration is always done in color mode */
- channels = 3;
-
- unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres);
- unsigned factor = sensor.optical_res / resolution;
-
- const auto& calib_sensor_base = sanei_genesys_find_sensor(dev, resolution, channels,
- dev->settings.scan_method);
-
- num_pixels = calib_sensor_base.sensor_pixels / factor;
-
- ScanSession session;
- session.params.xres = resolution;
- session.params.yres = dev->settings.yres;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = num_pixels;
- session.params.lines = 1;
- session.params.depth = 16;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, calib_sensor_base);
-
- init_regs_for_scan_session(dev, calib_sensor_base, &regs, session);
-
- dev->interface->write_registers(regs);
-
-
- total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */
-
- std::vector<uint8_t> line(total_size);
-
-/*
- we try to get equal bright leds here:
-
- loop:
- average per color
- adjust exposure times
- */
-
- exp[0] = sensor.exposure.red;
- exp[1] = sensor.exposure.green;
- exp[2] = sensor.exposure.blue;
-
- turn = 0;
- /* max exposure is set to ~2 time initial average
- * exposure, or 2 time last calibration exposure */
- max_exposure=((exp[0]+exp[1]+exp[2])/3)*2;
- target=sensor.gain_white_ref*256;
-
- auto calib_sensor = calib_sensor_base;
-
- bool acceptable = false;
- do {
- calib_sensor.exposure.red = exp[0];
- calib_sensor.exposure.green = exp[1];
- calib_sensor.exposure.blue = exp[2];
-
- regs_set_exposure(dev->model->asic_type, regs, calib_sensor.exposure);
- dev->interface->write_register(0x10, (calib_sensor.exposure.red >> 8) & 0xff);
- dev->interface->write_register(0x11, calib_sensor.exposure.red & 0xff);
- dev->interface->write_register(0x12, (calib_sensor.exposure.green >> 8) & 0xff);
- dev->interface->write_register(0x13, calib_sensor.exposure.green & 0xff);
- dev->interface->write_register(0x14, (calib_sensor.exposure.blue >> 8) & 0xff);
- dev->interface->write_register(0x15, calib_sensor.exposure.blue & 0xff);
-
- dev->interface->write_registers(regs);
-
- DBG(DBG_info, "%s: starting line reading\n", __func__);
- dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("led_calibration");
- move_back_home(dev, true);
- return calib_sensor.exposure;
- }
-
- sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
-
- if (DBG_LEVEL >= DBG_data) {
- char fn[30];
- std::snprintf(fn, 30, "gl841_led_%d.pnm", turn);
- sanei_genesys_write_pnm_file(fn, line.data(), 16, channels, num_pixels, 1);
- }
-
- /* compute average */
- for (j = 0; j < channels; j++)
- {
- avg[j] = 0;
- for (i = 0; i < num_pixels; i++)
- {
- if (dev->model->is_cis)
- val =
- line[i * 2 + j * 2 * num_pixels + 1] * 256 +
- line[i * 2 + j * 2 * num_pixels];
- else
- val =
- line[i * 2 * channels + 2 * j + 1] * 256 +
- line[i * 2 * channels + 2 * j];
- avg[j] += val;
- }
-
- avg[j] /= num_pixels;
- }
-
- DBG(DBG_info,"%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]);
-
- acceptable = true;
-
- /* exposure is acceptable if each color is in the %5 range
- * of other color channels */
- if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 ||
- avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 ||
- avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95)
- {
- acceptable = false;
- }
-
- /* led exposure is not acceptable if white level is too low
- * ~80 hardcoded value for white level */
- if(avg[0]<20000 || avg[1]<20000 || avg[2]<20000)
- {
- acceptable = false;
- }
-
- /* for scanners using target value */
- if(target>0)
- {
- acceptable = true;
- for(i=0;i<3;i++)
- {
- /* we accept +- 2% delta from target */
- if(abs(avg[i]-target)>target/50)
- {
- exp[i]=(exp[i]*target)/avg[i];
- acceptable = false;
- }
- }
- }
- else
- {
- if (!acceptable)
- {
- avga = (avg[0]+avg[1]+avg[2])/3;
- exp[0] = (exp[0] * avga) / avg[0];
- exp[1] = (exp[1] * avga) / avg[1];
- exp[2] = (exp[2] * avga) / avg[2];
- /*
- keep the resulting exposures below this value.
- too long exposure drives the ccd into saturation.
- we may fix this by relying on the fact that
- we get a striped scan without shading, by means of
- statistical calculation
- */
- avge = (exp[0] + exp[1] + exp[2]) / 3;
-
- if (avge > max_exposure) {
- exp[0] = (exp[0] * max_exposure) / avge;
- exp[1] = (exp[1] * max_exposure) / avge;
- exp[2] = (exp[2] * max_exposure) / avge;
- }
- if (avge < min_exposure) {
- exp[0] = (exp[0] * min_exposure) / avge;
- exp[1] = (exp[1] * min_exposure) / avge;
- exp[2] = (exp[2] * min_exposure) / avge;
- }
-
- }
- }
-
- gl841_stop_action(dev);
-
- turn++;
-
- } while (!acceptable && turn < 100);
-
- DBG(DBG_info,"%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]);
-
- dev->cmd_set->move_back_home(dev, true);
-
- return calib_sensor.exposure;
+ return scanner_led_calibration(*dev, sensor, regs);
}
/** @brief calibration for AD frontend devices
@@ -2804,9 +1663,6 @@ static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor&
Genesys_Register_Set& regs)
{
DBG_HELPER(dbg);
- int num_pixels;
- int total_size;
- int i;
int average;
int turn;
int top;
@@ -2818,14 +1674,12 @@ static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor&
return;
}
- unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres);
- unsigned factor = sensor.optical_res / resolution;
+ unsigned resolution = sensor.shading_resolution;
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3,
dev->settings.scan_method);
- num_pixels = calib_sensor.sensor_pixels / factor;
-
+ unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
ScanSession session;
session.params.xres = resolution;
session.params.yres = dev->settings.yres;
@@ -2841,14 +1695,15 @@ static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor&
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, calib_sensor);
dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &regs, session);
- total_size = num_pixels * 3 * 2 * 1;
-
- std::vector<uint8_t> line(total_size);
+ // FIXME: we're reading twice as much data for no reason
+ std::size_t total_size = session.output_line_bytes * 2;
+ std::vector<uint8_t> line(total_size);
dev->frontend.set_gain(0, 0);
dev->frontend.set_gain(1, 0);
@@ -2873,23 +1728,23 @@ static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor&
if (is_testing_mode()) {
dev->interface->test_checkpoint("ad_fe_offset_calibration");
- gl841_stop_action(dev);
+ scanner_stop_action(*dev);
return;
}
sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
- gl841_stop_action (dev);
- if (DBG_LEVEL >= DBG_data) {
+ scanner_stop_action(*dev);
+ if (dbg_log_image_data()) {
char fn[30];
- std::snprintf(fn, 30, "gl841_offset_%02d.pnm", turn);
- sanei_genesys_write_pnm_file(fn, line.data(), 8, 3, num_pixels, 1);
+ std::snprintf(fn, 30, "gl841_offset_%02d.tiff", turn);
+ write_tiff_file(fn, line.data(), 8, 3, num_pixels, 1);
}
/* search for minimal value */
average=0;
- for(i=0;i<total_size;i++)
+ for (std::size_t i = 0; i < total_size; i++)
{
- average+=line[i];
+ average += line[i];
}
average/=total_size;
DBG(DBG_data, "%s: average=%d\n", __func__, average);
@@ -2919,8 +1774,6 @@ static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor&
/* this function does the offset calibration by scanning one line of the calibration
area below scanner's top. There is a black margin and the remaining is white.
- sanei_genesys_search_start() must have been called so that the offsets and margins
- are allready known.
this function expects the slider to be where?
*/
@@ -2928,39 +1781,32 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
- int num_pixels;
- int total_size;
- int i, j;
- int val;
- int channels;
int off[3],offh[3],offl[3],off1[3],off2[3];
int min1[3],min2[3];
- int cmin[3],cmax[3];
+ unsigned cmin[3],cmax[3];
int turn;
int mintgt = 0x400;
/* Analog Device fronted have a different calibration */
if ((dev->reg.find_reg(0x04).value & REG_0x04_FESET) == 0x02) {
- return ad_fe_offset_calibration(dev, sensor, regs);
+ ad_fe_offset_calibration(dev, sensor, regs);
+ return;
}
/* offset calibration is always done in color mode */
- channels = 3;
+ unsigned channels = 3;
- unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres);
- unsigned factor = sensor.optical_res / resolution;
+ unsigned resolution = sensor.shading_resolution;
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
- num_pixels = calib_sensor.sensor_pixels / factor;
-
ScanSession session;
session.params.xres = resolution;
session.params.yres = dev->settings.yres;
session.params.startx = 0;
session.params.starty = 0;
- session.params.pixels = num_pixels;
+ session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
session.params.lines = 1;
session.params.depth = 16;
session.params.channels = channels;
@@ -2970,17 +1816,13 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE |
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET |
ScanFlag::DISABLE_LAMP;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
- total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */
-
- std::vector<uint8_t> first_line(total_size);
- std::vector<uint8_t> second_line(total_size);
-
/* scan first line of data with no offset nor gain */
/*WM8199: gain=0.73; offset=-260mV*/
/*okay. the sensor black level is now at -260mV. we only get 0 from AFE...*/
@@ -3011,12 +1853,14 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
offl[2] = 0x00;
turn = 0;
+ Image first_line;
+
bool acceptable = false;
do {
dev->interface->write_registers(regs);
- for (j=0; j < channels; j++) {
+ for (unsigned j = 0; j < channels; j++) {
off[j] = (offh[j]+offl[j])/2;
dev->frontend.set_offset(j, off[j]);
}
@@ -3031,57 +1875,51 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
return;
}
- sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size);
+ first_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
- if (DBG_LEVEL >= DBG_data) {
- char fn[30];
- std::snprintf(fn, 30, "gl841_offset1_%02d.pnm", turn);
- sanei_genesys_write_pnm_file(fn, first_line.data(), 16, channels, num_pixels, 1);
- }
+ if (dbg_log_image_data()) {
+ char fn[30];
+ std::snprintf(fn, 30, "gl841_offset1_%02d.tiff", turn);
+ write_tiff_file(fn, first_line);
+ }
acceptable = true;
- for (j = 0; j < channels; j++)
- {
- cmin[j] = 0;
- cmax[j] = 0;
+ for (unsigned ch = 0; ch < channels; ch++) {
+ cmin[ch] = 0;
+ cmax[ch] = 0;
- for (i = 0; i < num_pixels; i++)
- {
- if (dev->model->is_cis)
- val =
- first_line[i * 2 + j * 2 * num_pixels + 1] * 256 +
- first_line[i * 2 + j * 2 * num_pixels];
- else
- val =
- first_line[i * 2 * channels + 2 * j + 1] * 256 +
- first_line[i * 2 * channels + 2 * j];
- if (val < 10)
- cmin[j]++;
- if (val > 65525)
- cmax[j]++;
- }
+ for (std::size_t x = 0; x < first_line.get_width(); x++) {
+ auto value = first_line.get_raw_channel(x, 0, ch);
+ if (value < 10) {
+ cmin[ch]++;
+ }
+ if (value > 65525) {
+ cmax[ch]++;
+ }
+ }
/* TODO the DP685 has a black strip in the middle of the sensor
* should be handled in a more elegant way , could be a bug */
- if (dev->model->sensor_id == SensorId::CCD_DP685)
- cmin[j] -= 20;
+ if (dev->model->sensor_id == SensorId::CCD_DP685) {
+ cmin[ch] -= 20;
+ }
- if (cmin[j] > num_pixels/100) {
+ if (cmin[ch] > first_line.get_width() / 100) {
acceptable = false;
if (dev->model->is_cis)
offl[0] = off[0];
else
- offl[j] = off[j];
- }
- if (cmax[j] > num_pixels/100) {
+ offl[ch] = off[ch];
+ }
+ if (cmax[ch] > first_line.get_width() / 100) {
acceptable = false;
if (dev->model->is_cis)
offh[0] = off[0];
else
- offh[j] = off[j];
- }
- }
+ offh[ch] = off[ch];
+ }
+ }
DBG(DBG_info,"%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0],
cmin[1], cmax[1], cmin[2], cmax[2]);
@@ -3091,7 +1929,7 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
offl[2] = offl[1] = offl[0];
}
- gl841_stop_action(dev);
+ scanner_stop_action(*dev);
turn++;
} while (!acceptable && turn < 100);
@@ -3099,26 +1937,19 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
DBG(DBG_info,"%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]);
- for (j = 0; j < channels; j++)
- {
- off1[j] = off[j];
+ for (unsigned ch = 0; ch < channels; ch++) {
+ off1[ch] = off[ch];
- min1[j] = 65536;
+ min1[ch] = 65536;
- for (i = 0; i < num_pixels; i++)
- {
- if (dev->model->is_cis)
- val =
- first_line[i * 2 + j * 2 * num_pixels + 1] * 256 +
- first_line[i * 2 + j * 2 * num_pixels];
- else
- val =
- first_line[i * 2 * channels + 2 * j + 1] * 256 +
- first_line[i * 2 * channels + 2 * j];
- if (min1[j] > val && val >= 10)
- min1[j] = val;
- }
- }
+ for (std::size_t x = 0; x < first_line.get_width(); x++) {
+ auto value = first_line.get_raw_channel(x, 0, ch);
+
+ if (min1[ch] > value && value >= 10) {
+ min1[ch] = value;
+ }
+ }
+ }
offl[0] = off[0];
@@ -3126,64 +1957,59 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
offl[2] = off[0];
turn = 0;
+ Image second_line;
do {
- for (j=0; j < channels; j++) {
+ for (unsigned j=0; j < channels; j++) {
off[j] = (offh[j]+offl[j])/2;
dev->frontend.set_offset(j, off[j]);
- }
+ }
dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
DBG(DBG_info, "%s: starting second line reading\n", __func__);
dev->interface->write_registers(regs);
dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
- sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
+ second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
- if (DBG_LEVEL >= DBG_data) {
- char fn[30];
- std::snprintf(fn, 30, "gl841_offset2_%02d.pnm", turn);
- sanei_genesys_write_pnm_file(fn, second_line.data(), 16, channels, num_pixels, 1);
- }
+ if (dbg_log_image_data()) {
+ char fn[30];
+ std::snprintf(fn, 30, "gl841_offset2_%02d.tiff", turn);
+ write_tiff_file(fn, second_line);
+ }
acceptable = true;
- for (j = 0; j < channels; j++)
- {
- cmin[j] = 0;
- cmax[j] = 0;
+ for (unsigned ch = 0; ch < channels; ch++) {
+ cmin[ch] = 0;
+ cmax[ch] = 0;
- for (i = 0; i < num_pixels; i++)
- {
- if (dev->model->is_cis)
- val =
- second_line[i * 2 + j * 2 * num_pixels + 1] * 256 +
- second_line[i * 2 + j * 2 * num_pixels];
- else
- val =
- second_line[i * 2 * channels + 2 * j + 1] * 256 +
- second_line[i * 2 * channels + 2 * j];
- if (val < 10)
- cmin[j]++;
- if (val > 65525)
- cmax[j]++;
- }
+ for (std::size_t x = 0; x < second_line.get_width(); x++) {
+ auto value = second_line.get_raw_channel(x, 0, ch);
- if (cmin[j] > num_pixels/100) {
+ if (value < 10) {
+ cmin[ch]++;
+ }
+ if (value > 65525) {
+ cmax[ch]++;
+ }
+ }
+
+ if (cmin[ch] > second_line.get_width() / 100) {
acceptable = false;
if (dev->model->is_cis)
offl[0] = off[0];
else
- offl[j] = off[j];
- }
- if (cmax[j] > num_pixels/100) {
+ offl[ch] = off[ch];
+ }
+ if (cmax[ch] > second_line.get_width() / 100) {
acceptable = false;
if (dev->model->is_cis)
offh[0] = off[0];
else
- offh[j] = off[j];
- }
- }
+ offh[ch] = off[ch];
+ }
+ }
DBG(DBG_info, "%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0],
cmin[1], cmax[1], cmin[2], cmax[2]);
@@ -3193,7 +2019,7 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
offl[2] = offl[1] = offl[0];
}
- gl841_stop_action(dev);
+ scanner_stop_action(*dev);
turn++;
@@ -3202,26 +2028,19 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
DBG(DBG_info, "%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]);
- for (j = 0; j < channels; j++)
- {
- off2[j] = off[j];
+ for (unsigned ch = 0; ch < channels; ch++) {
+ off2[ch] = off[ch];
- min2[j] = 65536;
+ min2[ch] = 65536;
- for (i = 0; i < num_pixels; i++)
- {
- if (dev->model->is_cis)
- val =
- second_line[i * 2 + j * 2 * num_pixels + 1] * 256 +
- second_line[i * 2 + j * 2 * num_pixels];
- else
- val =
- second_line[i * 2 * channels + 2 * j + 1] * 256 +
- second_line[i * 2 * channels + 2 * j];
- if (min2[j] > val && val != 0)
- min2[j] = val;
- }
- }
+ for (std::size_t x = 0; x < second_line.get_width(); x++) {
+ auto value = second_line.get_raw_channel(x, 0, ch);
+
+ if (min2[ch] > value && value != 0) {
+ min2[ch] = value;
+ }
+ }
+ }
DBG(DBG_info, "%s: first set: %d/%d,%d/%d,%d/%d\n", __func__, off1[0], min1[0], off1[1], min1[1],
off1[2], min1[2]);
@@ -3247,22 +2066,25 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
off=(min*(off1-off2)+min1*off2-off1*min2)/(min1-min2)
*/
- for (j = 0; j < channels; j++)
- {
- if (min2[j]-min1[j] == 0) {
+ for (unsigned ch = 0; ch < channels; ch++) {
+ if (min2[ch] - min1[ch] == 0) {
/*TODO: try to avoid this*/
DBG(DBG_warn, "%s: difference too small\n", __func__);
- if (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j] >= 0)
- off[j] = 0x0000;
- else
- off[j] = 0xffff;
- } else
- off[j] = (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j])/(min1[j]-min2[j]);
- if (off[j] > 255)
- off[j] = 255;
- if (off[j] < 0)
- off[j] = 0;
- dev->frontend.set_offset(j, off[j]);
+ if (mintgt * (off1[ch] - off2[ch]) + min1[ch] * off2[ch] - min2[ch] * off1[ch] >= 0) {
+ off[ch] = 0x0000;
+ } else {
+ off[ch] = 0xffff;
+ }
+ } else {
+ off[ch] = (mintgt * (off1[ch] - off2[ch]) + min1[ch] * off2[ch] - min2[ch] * off1[ch])/(min1[ch]-min2[ch]);
+ }
+ if (off[ch] > 255) {
+ off[ch] = 255;
+ }
+ if (off[ch] < 0) {
+ off[ch] = 0;
+ }
+ dev->frontend.set_offset(ch, off[ch]);
}
DBG(DBG_info, "%s: final offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]);
@@ -3297,171 +2119,13 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
void CommandSetGl841::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const
{
- DBG_HELPER_ARGS(dbg, "dpi=%d", dpi);
- int num_pixels;
- int total_size;
- int i, j, channels;
- int max[3];
- float gain[3];
- int val;
- int lines=1;
- int move;
-
- // feed to white strip if needed
- if (dev->model->y_offset_calib_white > 0) {
- move = static_cast<int>(dev->model->y_offset_calib_white);
- move = static_cast<int>((move * (dev->motor.base_ydpi)) / MM_PER_INCH);
- DBG(DBG_io, "%s: move=%d lines\n", __func__, move);
- gl841_feed(dev, move);
- }
-
- /* coarse gain calibration is allways done in color mode */
- channels = 3;
-
- unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres);
- unsigned factor = sensor.optical_res / resolution;
-
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
- dev->settings.scan_method);
-
- num_pixels = calib_sensor.sensor_pixels / factor;
-
- ScanSession session;
- session.params.xres = resolution;
- session.params.yres = dev->settings.yres;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = num_pixels;
- session.params.lines = lines;
- session.params.depth = 16;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, calib_sensor);
-
- init_regs_for_scan_session(dev, calib_sensor, &regs, session);
-
- dev->interface->write_registers(regs);
-
- total_size = num_pixels * channels * 2 * lines; /* colors * bytes_per_color * scan lines */
-
- std::vector<uint8_t> line(total_size);
-
- dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("coarse_gain_calibration");
- gl841_stop_action(dev);
- move_back_home(dev, true);
- return;
- }
-
- sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
-
- if (DBG_LEVEL >= DBG_data)
- sanei_genesys_write_pnm_file("gl841_gain.pnm", line.data(), 16, channels, num_pixels, lines);
-
- /* average high level for each channel and compute gain
- to reach the target code
- we only use the central half of the CCD data */
- for (j = 0; j < channels; j++)
- {
- max[j] = 0;
- for (i = 0; i < num_pixels; i++)
- {
- if (dev->model->is_cis)
- val =
- line[i * 2 + j * 2 * num_pixels + 1] * 256 +
- line[i * 2 + j * 2 * num_pixels];
- else
- val =
- line[i * 2 * channels + 2 * j + 1] * 256 +
- line[i * 2 * channels + 2 * j];
-
- if (val > max[j])
- max[j] = val;
- }
-
- gain[j] = 65535.0f / max[j];
-
- uint8_t out_gain = 0;
-
- if (dev->model->adc_id == AdcId::CANON_LIDE_35 ||
- dev->model->adc_id == AdcId::WOLFSON_XP300 ||
- dev->model->adc_id == AdcId::WOLFSON_DSM600)
- {
- gain[j] *= 0.69f; // seems we don't get the real maximum. empirically derived
- if (283 - 208/gain[j] > 255)
- out_gain = 255;
- else if (283 - 208/gain[j] < 0)
- out_gain = 0;
- else
- out_gain = static_cast<std::uint8_t>(283 - 208 / gain[j]);
- } else if (dev->model->adc_id == AdcId::CANON_LIDE_80) {
- out_gain = static_cast<std::uint8_t>(gain[j] * 12);
- }
- dev->frontend.set_gain(j, out_gain);
-
- DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j],
- out_gain);
- }
-
- for (j = 0; j < channels; j++)
- {
- if(gain[j] > 10)
- {
- DBG (DBG_error0, "**********************************************\n");
- DBG (DBG_error0, "**********************************************\n");
- DBG (DBG_error0, "**** ****\n");
- DBG (DBG_error0, "**** Extremely low Brightness detected. ****\n");
- DBG (DBG_error0, "**** Check the scanning head is ****\n");
- DBG (DBG_error0, "**** unlocked and moving. ****\n");
- DBG (DBG_error0, "**** ****\n");
- DBG (DBG_error0, "**********************************************\n");
- DBG (DBG_error0, "**********************************************\n");
- throw SaneException(SANE_STATUS_JAMMED, "scanning head is locked");
- }
-
- }
-
- if (dev->model->is_cis) {
- uint8_t gain0 = dev->frontend.get_gain(0);
- if (gain0 > dev->frontend.get_gain(1)) {
- gain0 = dev->frontend.get_gain(1);
- }
- if (gain0 > dev->frontend.get_gain(2)) {
- gain0 = dev->frontend.get_gain(2);
- }
- dev->frontend.set_gain(0, gain0);
- dev->frontend.set_gain(1, gain0);
- dev->frontend.set_gain(2, gain0);
- }
-
- if (channels == 1) {
- dev->frontend.set_gain(0, dev->frontend.get_gain(1));
- dev->frontend.set_gain(2, dev->frontend.get_gain(1));
- }
-
- DBG(DBG_info, "%s: gain=(%d,%d,%d)\n", __func__,
- dev->frontend.get_gain(0),
- dev->frontend.get_gain(1),
- dev->frontend.get_gain(2));
-
- gl841_stop_action(dev);
-
- dev->cmd_set->move_back_home(dev, true);
+ scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
}
// wait for lamp warmup by scanning the same line until difference
// between 2 scans is below a threshold
void CommandSetGl841::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* local_reg, int* channels,
- int* total_size) const
+ Genesys_Register_Set* local_reg) const
{
DBG_HELPER(dbg);
int num_pixels = 4 * 300;
@@ -3475,51 +2139,34 @@ void CommandSetGl841::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Se
dev->frontend.set_offset(1, 0x80);
dev->frontend.set_offset(2, 0x80);
+ auto flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA |
+ ScanFlag::SINGLE_LINE |
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ flags |= ScanFlag::USE_XPA;
+ }
+
ScanSession session;
- session.params.xres = sensor.optical_res;
+ session.params.xres = sensor.full_resolution;
session.params.yres = dev->settings.yres;
session.params.startx = sensor.dummy_pixel;
session.params.starty = 0;
session.params.pixels = num_pixels;
session.params.lines = 1;
- session.params.depth = 16;
- session.params.channels = *channels;
+ session.params.depth = dev->model->bpp_color_values.front();
+ session.params.channels = 3;
session.params.scan_method = dev->settings.scan_method;
- if (*channels == 3) {
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- } else {
- session.params.scan_mode = ScanColorMode::GRAY;
- }
+ session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
+ session.params.flags = flags;
+
compute_session(dev, session, sensor);
init_regs_for_scan_session(dev, sensor, local_reg, session);
-
- num_pixels = session.output_pixels;
-
- *total_size = num_pixels * 3 * 2 * 1; /* colors * bytes_per_color * scan lines */
-
- dev->interface->write_registers(*local_reg);
-}
-
-
-/*
- * this function moves head without scanning, forward, then backward
- * so that the head goes to park position.
- * as a by-product, also check for lock
- */
-static void sanei_gl841_repark_head(Genesys_Device* dev)
-{
- DBG_HELPER(dbg);
-
- gl841_feed(dev,232);
-
- // toggle motor flag, put an huge step number and redo move backward
- dev->cmd_set->move_back_home(dev, true);
}
/*
@@ -3528,123 +2175,9 @@ static void sanei_gl841_repark_head(Genesys_Device* dev)
*/
void CommandSetGl841::init(Genesys_Device* dev) const
{
- size_t size;
-
- DBG_INIT ();
+ DBG_INIT();
DBG_HELPER(dbg);
-
- dev->set_head_pos_zero(ScanHeadId::PRIMARY);
-
- /* Check if the device has already been initialized and powered up */
- if (dev->already_initialized)
- {
- auto status = scanner_read_status(*dev);
- if (!status.is_replugged) {
- DBG(DBG_info, "%s: already initialized\n", __func__);
- return;
- }
- }
-
- dev->dark_average_data.clear();
- dev->white_average_data.clear();
-
- dev->settings.color_filter = ColorFilter::RED;
-
- // ASIC reset
- dev->interface->write_register(0x0e, 0x01);
- dev->interface->write_register(0x0e, 0x00);
-
- /* Set default values for registers */
- gl841_init_registers (dev);
-
- // Write initial registers
- dev->interface->write_registers(dev->reg);
-
- const auto& sensor = sanei_genesys_find_sensor_any(dev);
-
- // Set analog frontend
- dev->cmd_set->set_fe(dev, sensor, AFE_INIT);
-
- // FIXME: move_back_home modifies dev->calib_reg and requires it to be filled
- dev->calib_reg = dev->reg;
-
- // Move home
- dev->cmd_set->move_back_home(dev, true);
-
- // Init shading data
- sanei_genesys_init_shading_data(dev, sensor, sensor.sensor_pixels);
-
- /* ensure head is correctly parked, and check lock */
- if (dev->model->flags & GENESYS_FLAG_REPARK)
- {
- // FIXME: if repark fails, we should print an error message that the scanner is locked and
- // the user should unlock the lock. We should also rethrow with SANE_STATUS_JAMMED
- sanei_gl841_repark_head(dev);
- }
-
- // send gamma tables
- dev->cmd_set->send_gamma_table(dev, sensor);
-
- /* initial calibration reg values */
- Genesys_Register_Set& regs = dev->calib_reg;
- regs = dev->reg;
-
- unsigned resolution = sensor.get_logical_hwdpi(300);
- unsigned factor = sensor.optical_res / resolution;
-
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3,
- dev->settings.scan_method);
-
- unsigned num_pixels = 16 / factor;
-
- ScanSession session;
- session.params.xres = resolution;
- session.params.yres = 300;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = num_pixels;
- session.params.lines = 1;
- session.params.depth = 16;
- session.params.channels = 3;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = ColorFilter::RED;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, calib_sensor);
-
- init_regs_for_scan_session(dev, calib_sensor, &regs, session);
-
- dev->interface->write_registers(regs);
-
- size = num_pixels * 3 * 2 * 1; // colors * bytes_per_color * scan lines
-
- std::vector<uint8_t> line(size);
-
- DBG(DBG_info, "%s: starting dummy data reading\n", __func__);
- dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
-
- sanei_usb_set_timeout(1000);/* 1 second*/
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("init");
- } else {
- // ignore errors. next read will succeed
- catch_all_exceptions(__func__,
- [&](){ sanei_genesys_read_data_from_scanner(dev, line.data(), size); });
- }
-
- sanei_usb_set_timeout(30 * 1000);/* 30 seconds*/
-
- end_scan(dev, &regs, true);
-
- regs = dev->reg;
-
- // Set powersaving(default = 15 minutes)
- set_powersaving(dev, 15);
- dev->already_initialized = true;
+ sanei_genesys_asic_init(dev);
}
void CommandSetGl841::update_hardware_sensors(Genesys_Scanner* s) const
@@ -3676,225 +2209,6 @@ void CommandSetGl841::update_hardware_sensors(Genesys_Scanner* s) const
}
}
-/** @brief 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 CommandSetGl841::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward,
- bool black) const
-{
- DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse");
- unsigned int pixels, lines, channels;
- Genesys_Register_Set local_reg;
- size_t size;
- unsigned int pass, count, found, x, y, length;
- char title[80];
- GenesysRegister *r;
- uint8_t white_level=90; /**< default white level to detect white dots */
- uint8_t black_level=60; /**< default black level to detect black dots */
-
- /* use maximum gain when doing forward white strip detection
- * since we don't have calibrated the sensor yet */
- if(!black && forward)
- {
- dev->frontend.set_gain(0, 0xff);
- dev->frontend.set_gain(1, 0xff);
- dev->frontend.set_gain(2, 0xff);
- }
-
- dev->cmd_set->set_fe(dev, sensor, AFE_SET);
- gl841_stop_action(dev);
-
- // set up for a gray scan at lowest dpi
- const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method);
- unsigned dpi = resolution_settings.get_min_resolution_x();
- channels = 1;
-
- /* shading calibation is done with dev->motor.base_ydpi */
- /* lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; */
- lines = static_cast<unsigned>((10 * dpi) / MM_PER_INCH);
-
- pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res;
-
- /* 20 cm max length for calibration sheet */
- length = static_cast<unsigned>(((200 * dpi) / MM_PER_INCH) / lines);
-
- dev->set_head_pos_zero(ScanHeadId::PRIMARY);
-
- local_reg = dev->reg;
-
- ScanSession session;
- session.params.xres = dpi;
- session.params.yres = dpi;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = pixels;
- session.params.lines = lines;
- session.params.depth = 8;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::GRAY;
- session.params.color_filter = ColorFilter::RED;
- session.params.flags = ScanFlag::DISABLE_SHADING | ScanFlag::DISABLE_GAMMA;
- compute_session(dev, session, sensor);
-
- size = pixels * channels * lines * (session.params.depth / 8);
- std::vector<uint8_t> data(size);
-
- init_regs_for_scan_session(dev, sensor, &local_reg, session);
-
- /* set up for reverse or forward */
- r = sanei_genesys_get_address(&local_reg, 0x02);
- if (forward) {
- r->value &= ~4;
- } else {
- r->value |= 4;
- }
-
- dev->interface->write_registers(local_reg);
-
- dev->cmd_set->begin_scan(dev, sensor, &local_reg, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("search_strip");
- gl841_stop_action(dev);
- return;
- }
-
- // waits for valid data
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- sanei_genesys_read_data_from_scanner(dev, data.data(), size);
-
- gl841_stop_action(dev);
-
- pass = 0;
- if (DBG_LEVEL >= DBG_data)
- {
- std::sprintf(title, "gl841_search_strip_%s_%s%02u.pnm", black ? "black" : "white",
- forward ? "fwd" : "bwd", pass);
- sanei_genesys_write_pnm_file(title, data.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- /* loop until strip is found or maximum pass number done */
- found = 0;
- while (pass < length && !found)
- {
- dev->interface->write_registers(local_reg);
-
- //now start scan
- dev->cmd_set->begin_scan(dev, sensor, &local_reg, true);
-
- // waits for valid data
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- sanei_genesys_read_data_from_scanner(dev, data.data(), size);
-
- gl841_stop_action (dev);
-
- if (DBG_LEVEL >= DBG_data)
- {
- std::sprintf(title, "gl841_search_strip_%s_%s%02u.pnm",
- black ? "black" : "white", forward ? "fwd" : "bwd", pass);
- sanei_genesys_write_pnm_file(title, data.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- /* search data to find black strip */
- /* when searching forward, we only need one line of the searched color since we
- * will scan forward. But when doing backward search, we need all the area of the
- * same color */
- if (forward)
- {
- for (y = 0; y < lines && !found; y++)
- {
- count = 0;
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < pixels; x++)
- {
- /* when searching for black, detect white pixels */
- if (black && data[y * pixels + x] > white_level)
- {
- count++;
- }
- /* when searching for white, detect black pixels */
- if (!black && data[y * pixels + x] < black_level)
- {
- count++;
- }
- }
-
- /* at end of line, if count >= 3%, line is not fully of the desired color
- * so we must go to next line of the buffer */
- /* count*100/pixels < 3 */
- if ((count * 100) / pixels < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__,
- pass, y);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
- (100 * count) / pixels);
- }
- }
- }
- else /* since calibration scans are done forward, we need the whole area
- to be of the required color when searching backward */
- {
- count = 0;
- for (y = 0; y < lines; y++)
- {
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < pixels; x++)
- {
- /* when searching for black, detect white pixels */
- if (black && data[y * pixels + x] > white_level)
- {
- count++;
- }
- /* when searching for white, detect black pixels */
- if (!black && data[y * pixels + x] < black_level)
- {
- count++;
- }
- }
- }
-
- /* at end of area, if count >= 3%, area is not fully of the desired color
- * so we must go to next buffer */
- if ((count * 100) / (pixels * lines) < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
- (100 * count) / pixels);
- }
- }
- pass++;
- }
-
- if (found)
- {
- DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white");
- }
- else
- {
- throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white");
- }
-}
-
/**
* Send shading calibration data. The buffer is considered to always hold values
* for all the channels.
@@ -3903,42 +2217,30 @@ void CommandSetGl841::send_shading_data(Genesys_Device* dev, const Genesys_Senso
uint8_t* data, int size) const
{
DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size);
- uint32_t length, x, factor, pixels, i;
- uint16_t dpiset, dpihw, beginpixel;
+ uint32_t length, x, pixels, i;
uint8_t *ptr,*src;
/* old method if no SHDAREA */
if ((dev->reg.find_reg(0x01).value & REG_0x01_SHDAREA) == 0) {
+ // Note that this requires the sensor pixel offset to be exactly the same as to start
+ // reading from dummy_pixel + 1 position.
dev->interface->write_buffer(0x3c, 0x0000, data, size);
return;
}
/* data is whole line, we extract only the part for the scanned area */
length = static_cast<std::uint32_t>(size / 3);
- unsigned strpixel = dev->session.pixel_startx;
- unsigned endpixel = dev->session.pixel_endx;
-
- /* compute deletion/average factor */
- dpiset = dev->reg.get16(REG_DPISET);
- dpihw = gl841_get_dpihw(dev);
- unsigned ccd_size_divisor = dev->session.ccd_size_divisor;
- factor=dpihw/dpiset;
- DBG(DBG_io2, "%s: dpihw=%d, dpiset=%d, ccd_size_divisor=%d, factor=%d\n", __func__, dpihw, dpiset,
- ccd_size_divisor, factor);
-
- /* turn pixel value into bytes 2x16 bits words */
- strpixel*=2*2; /* 2 words of 2 bytes */
- endpixel*=2*2;
- pixels=endpixel-strpixel;
-
- /* shading pixel begin is start pixel minus start pixel during shading
- * calibration. Currently only cases handled are full and half ccd resolution.
- */
- beginpixel = sensor.ccd_start_xoffset / ccd_size_divisor;
- beginpixel += sensor.dummy_pixel + 1;
- DBG(DBG_io2, "%s: ORIGIN PIXEL=%d\n", __func__, beginpixel);
- beginpixel = (strpixel-beginpixel*2*2)/factor;
- DBG(DBG_io2, "%s: BEGIN PIXEL=%d\n", __func__, beginpixel/4);
+
+ // turn pixel value into bytes 2x16 bits words
+ pixels = dev->session.pixel_endx - dev->session.pixel_startx;
+ pixels *= 4;
+
+ // shading pixel begin is start pixel minus start pixel during shading
+ // calibration. Currently only cases handled are full and half ccd resolution.
+ unsigned beginpixel = dev->session.params.startx * dev->session.optical_resolution /
+ dev->session.params.xres;
+ beginpixel *= 4;
+ beginpixel /= sensor.shading_factor;
dev->interface->record_key_value("shading_offset", std::to_string(beginpixel));
dev->interface->record_key_value("shading_pixels", std::to_string(pixels));
@@ -3962,7 +2264,7 @@ void CommandSetGl841::send_shading_data(Genesys_Device* dev, const Genesys_Senso
for(x=0;x<pixels;x+=4)
{
/* coefficient source */
- src=data+x+beginpixel+i*length;
+ src = data + x + beginpixel + i * length;
ptr[0]=src[0];
ptr[1]=src[1];
ptr[2]=src[2];
@@ -3988,22 +2290,29 @@ void CommandSetGl841::wait_for_motor_stop(Genesys_Device* dev) const
(void) dev;
}
-void CommandSetGl841::move_to_ta(Genesys_Device* dev) const
-{
- (void) dev;
- throw SaneException("not implemented");
-}
-
void CommandSetGl841::asic_boot(Genesys_Device *dev, bool cold) const
{
- (void) dev;
- (void) cold;
- throw SaneException("not implemented");
-}
+ // reset ASIC in case of cold boot
+ if (cold) {
+ dev->interface->write_register(0x0e, 0x01);
+ dev->interface->write_register(0x0e, 0x00);
+ }
-std::unique_ptr<CommandSet> create_gl841_cmd_set()
-{
- return std::unique_ptr<CommandSet>(new CommandSetGl841{});
+ gl841_init_registers(dev);
+
+ // Write initial registers
+ dev->interface->write_registers(dev->reg);
+
+ // FIXME: 0x0b is not set, but on all other backends we do set it
+ // dev->reg.remove_reg(0x0b);
+
+ if (dev->model->model_id == ModelId::CANON_LIDE_60) {
+ dev->interface->write_0x8c(0x10, 0xa4);
+ }
+
+ // FIXME: we probably don't need this
+ const auto& sensor = sanei_genesys_find_sensor_any(dev);
+ dev->cmd_set->set_fe(dev, sensor, AFE_INIT);
}
} // namespace gl841
diff --git a/backend/genesys/gl841.h b/backend/genesys/gl841.h
index 5e24249..c9f15ee 100644
--- a/backend/genesys/gl841.h
+++ b/backend/genesys/gl841.h
@@ -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,17 +60,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs, int* channels,
- int* total_size) const override;
-
- 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_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@@ -86,8 +80,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,17 +95,14 @@ public:
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
+ 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,
int size) const override;
diff --git a/backend/genesys/gl841_registers.h b/backend/genesys/gl841_registers.h
index 8e0c204..2fac278 100644
--- a/backend/genesys/gl841_registers.h
+++ b/backend/genesys/gl841_registers.h
@@ -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;
diff --git a/backend/genesys/gl842.cpp b/backend/genesys/gl842.cpp
new file mode 100644
index 0000000..d5bebe5
--- /dev/null
+++ b/backend/genesys/gl842.cpp
@@ -0,0 +1,1066 @@
+/* sane - Scanner Access Now Easy.
+
+ Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr>
+ Copyright (C) 2020 Povilas Kanapickas <povilas@radix.lt>
+
+ This file is part of the SANE package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ As a special exception, the authors of SANE give permission for
+ additional uses of the libraries contained in this release of SANE.
+*/
+
+#define DEBUG_DECLARE_ONLY
+
+#include "gl842_registers.h"
+#include "gl842.h"
+#include "test_settings.h"
+
+#include <string>
+#include <vector>
+
+namespace genesys {
+namespace gl842 {
+
+static void gl842_init_registers(Genesys_Device& dev)
+{
+ // Within this function SENSOR_DEF marker documents that a register is part
+ // of the sensors definition and the actual value is set in
+ // gl842_setup_sensor().
+
+ DBG_HELPER(dbg);
+
+ dev.reg.clear();
+
+ if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
+ dev.reg.init_reg(0x01, 0x00);
+ dev.reg.init_reg(0x02, 0x78);
+ dev.reg.init_reg(0x03, 0xbf);
+ dev.reg.init_reg(0x04, 0x22);
+ dev.reg.init_reg(0x05, 0x48);
+
+ dev.reg.init_reg(0x06, 0xb8);
+
+ dev.reg.init_reg(0x07, 0x00);
+ dev.reg.init_reg(0x08, 0x00);
+ dev.reg.init_reg(0x09, 0x00);
+ dev.reg.init_reg(0x0a, 0x00);
+ dev.reg.init_reg(0x0d, 0x01);
+ } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
+ dev.reg.init_reg(0x01, 0x82);
+ dev.reg.init_reg(0x02, 0x10);
+ dev.reg.init_reg(0x03, 0x60);
+ dev.reg.init_reg(0x04, 0x10);
+ dev.reg.init_reg(0x05, 0x8c);
+
+ dev.reg.init_reg(0x06, 0x18);
+
+ //dev.reg.init_reg(0x07, 0x00);
+ dev.reg.init_reg(0x08, 0x00);
+ dev.reg.init_reg(0x09, 0x21);
+ dev.reg.init_reg(0x0a, 0x00);
+ dev.reg.init_reg(0x0d, 0x00);
+ }
+
+ dev.reg.init_reg(0x10, 0x00); // exposure, overwritten in scanner_setup_sensor() below
+ dev.reg.init_reg(0x11, 0x00); // exposure, overwritten in scanner_setup_sensor() below
+ dev.reg.init_reg(0x12, 0x00); // exposure, overwritten in scanner_setup_sensor() below
+ dev.reg.init_reg(0x13, 0x00); // exposure, overwritten in scanner_setup_sensor() below
+ dev.reg.init_reg(0x14, 0x00); // exposure, overwritten in scanner_setup_sensor() below
+ dev.reg.init_reg(0x15, 0x00); // exposure, overwritten in scanner_setup_sensor() below
+
+ // CCD signal settings.
+ dev.reg.init_reg(0x16, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x17, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x18, 0x00); // SENSOR_DEF
+
+ // EXPDMY[0:7]: Exposure time of dummy lines.
+ dev.reg.init_reg(0x19, 0x00); // SENSOR_DEF
+
+ // Various CCD clock settings.
+ dev.reg.init_reg(0x1a, 0x00); // SENSOR_DEF
+ if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
+ dev.reg.init_reg(0x1b, 0x00); // SENSOR_DEF
+ }
+ dev.reg.init_reg(0x1c, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x1d, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x1e, 0x10); // WDTIME, LINESEL: setup during sensor and motor setup
+
+ if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
+ dev.reg.init_reg(0x1f, 0x01);
+ dev.reg.init_reg(0x20, 0x27); // BUFSEL: buffer full condition
+ } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
+ dev.reg.init_reg(0x1f, 0x02);
+ dev.reg.init_reg(0x20, 0x02); // BUFSEL: buffer full condition
+ }
+
+ dev.reg.init_reg(0x21, 0x10); // STEPNO: set during motor setup
+ dev.reg.init_reg(0x22, 0x10); // FWDSTEP: set during motor setup
+ dev.reg.init_reg(0x23, 0x10); // BWDSTEP: set during motor setup
+ dev.reg.init_reg(0x24, 0x10); // FASTNO: set during motor setup
+ dev.reg.init_reg(0x25, 0x00); // LINCNT: set during motor setup
+ dev.reg.init_reg(0x26, 0x00); // LINCNT: set during motor setup
+ dev.reg.init_reg(0x27, 0x00); // LINCNT: set during motor setup
+
+ dev.reg.init_reg(0x29, 0xff); // LAMPPWM
+
+ dev.reg.init_reg(0x2c, 0x02); // DPISET: set during sensor setup
+ dev.reg.init_reg(0x2d, 0x58); // DPISET: set during sensor setup
+
+ dev.reg.init_reg(0x2e, 0x80); // BWHI: black/white low threshdold
+ dev.reg.init_reg(0x2f, 0x80); // BWLOW: black/white low threshold
+
+ dev.reg.init_reg(0x30, 0x00); // STRPIXEL: set during sensor setup
+ dev.reg.init_reg(0x31, 0x49); // STRPIXEL: set during sensor setup
+ dev.reg.init_reg(0x32, 0x53); // ENDPIXEL: set during sensor setup
+ dev.reg.init_reg(0x33, 0xb9); // ENDPIXEL: set during sensor setup
+
+ dev.reg.init_reg(0x34, 0x13); // DUMMY: SENSOR_DEF
+ dev.reg.init_reg(0x35, 0x00); // MAXWD: set during scan setup
+ dev.reg.init_reg(0x36, 0x40); // MAXWD: set during scan setup
+ dev.reg.init_reg(0x37, 0x00); // MAXWD: set during scan setup
+ dev.reg.init_reg(0x38, 0x2a); // LPERIOD: SENSOR_DEF
+ dev.reg.init_reg(0x39, 0xf8); // LPERIOD: SENSOR_DEF
+ dev.reg.init_reg(0x3d, 0x00); // FEEDL: set during motor setup
+ dev.reg.init_reg(0x3e, 0x00); // FEEDL: set during motor setup
+ dev.reg.init_reg(0x3f, 0x01); // FEEDL: set during motor setup
+
+ dev.reg.init_reg(0x52, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x53, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x54, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x55, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x56, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x57, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x58, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x59, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x5a, 0x00); // SENSOR_DEF
+
+ if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
+ dev.reg.init_reg(0x5e, 0x01); // DECSEL, STOPTIM
+ } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
+ dev.reg.init_reg(0x5e, 0x41); // DECSEL, STOPTIM
+ dev.reg.init_reg(0x5d, 0x20);
+ }
+ dev.reg.init_reg(0x5f, 0x10); // FMOVDEC: set during motor setup
+
+ dev.reg.init_reg(0x60, 0x00); // Z1MOD: overwritten during motor setup
+ dev.reg.init_reg(0x61, 0x00); // Z1MOD: overwritten during motor setup
+ dev.reg.init_reg(0x62, 0x00); // Z1MOD: overwritten during motor setup
+ dev.reg.init_reg(0x63, 0x00); // Z2MOD: overwritten during motor setup
+ dev.reg.init_reg(0x64, 0x00); // Z2MOD: overwritten during motor setup
+ dev.reg.init_reg(0x65, 0x00); // Z2MOD: overwritten during motor setup
+
+ if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
+ dev.reg.init_reg(0x67, 0x7f); // STEPSEL, MTRPWM: partially overwritten during motor setup
+ dev.reg.init_reg(0x68, 0x7f); // FSTPSEL, FASTPWM: partially overwritten during motor setup
+ } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
+ dev.reg.init_reg(0x66, 0x00); // PHFREQ
+ dev.reg.init_reg(0x67, 0x40); // STEPSEL, MTRPWM: partially overwritten during motor setup
+ dev.reg.init_reg(0x68, 0x40); // FSTPSEL, FASTPWM: partially overwritten during motor setup
+ }
+ dev.reg.init_reg(0x69, 0x10); // FSHDEC: overwritten during motor setup
+ dev.reg.init_reg(0x6a, 0x10); // FMOVNO: overwritten during motor setup
+
+ // 0x6b, 0x6c, 0x6d, 0x6e, 0x6f - set according to gpio tables. See gl842_init_gpio.
+
+ dev.reg.init_reg(0x70, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x71, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x72, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x73, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x74, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x75, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x76, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x77, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x78, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x79, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x7a, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x7b, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x7c, 0x00); // SENSOR_DEF
+ dev.reg.init_reg(0x7d, 0x00); // SENSOR_DEF
+
+ // 0x7e - set according to gpio tables. See gl842_init_gpio.
+
+ dev.reg.init_reg(0x7f, 0x00); // SENSOR_DEF
+
+ // VRHOME, VRMOVE, VRBACK, VRSCAN: Vref settings of the motor driver IC for
+ // moving in various situations.
+ dev.reg.init_reg(0x80, 0x00); // MOTOR_PROFILE
+
+ if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
+ dev.reg.init_reg(0x81, 0x00);
+ dev.reg.init_reg(0x82, 0x00);
+ dev.reg.init_reg(0x83, 0x00);
+ dev.reg.init_reg(0x84, 0x00);
+ dev.reg.init_reg(0x85, 0x00);
+ dev.reg.init_reg(0x86, 0x00);
+ dev.reg.init_reg(0x87, 0x00);
+ } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
+ dev.reg.init_reg(0x7e, 0x00);
+ dev.reg.init_reg(0x81, 0x00);
+ dev.reg.init_reg(0x82, 0x0f);
+ dev.reg.init_reg(0x83, 0x00);
+ dev.reg.init_reg(0x84, 0x0e);
+ dev.reg.init_reg(0x85, 0x00);
+ dev.reg.init_reg(0x86, 0x0d);
+ dev.reg.init_reg(0x87, 0x00);
+ dev.reg.init_reg(0x88, 0x00);
+ dev.reg.init_reg(0x89, 0x00);
+ }
+
+ const auto& sensor = sanei_genesys_find_sensor_any(&dev);
+ sanei_genesys_set_dpihw(dev.reg, sensor.register_dpihw);
+
+ scanner_setup_sensor(dev, sensor, dev.reg);
+}
+
+// Set values of analog frontend
+void CommandSetGl842::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const
+{
+ DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" :
+ set == AFE_SET ? "set" :
+ set == AFE_POWER_SAVE ? "powersave" : "huh?");
+ (void) sensor;
+
+ if (set == AFE_INIT) {
+ dev->frontend = dev->frontend_initial;
+ }
+
+ // check analog frontend type
+ // FIXME: looks like we write to that register with initial data
+ uint8_t fe_type = dev->interface->read_register(REG_0x04) & REG_0x04_FESET;
+ if (fe_type == 2 || dev->model->model_id == ModelId::CANON_LIDE_90) {
+ for (const auto& reg : dev->frontend.regs) {
+ dev->interface->write_fe_register(reg.address, reg.value);
+ }
+ return;
+ }
+ if (fe_type != 0) {
+ throw SaneException(SANE_STATUS_UNSUPPORTED, "unsupported frontend type %d", fe_type);
+ }
+
+ for (unsigned i = 1; i <= 3; i++) {
+ dev->interface->write_fe_register(i, dev->frontend.regs.get_value(0x00 + i));
+ }
+ for (const auto& reg : sensor.custom_fe_regs) {
+ dev->interface->write_fe_register(reg.address, reg.value);
+ }
+
+ for (unsigned i = 0; i < 3; i++) {
+ dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i));
+ }
+
+ for (unsigned i = 0; i < 3; i++) {
+ dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i));
+ }
+}
+
+static void gl842_init_motor_regs_scan(Genesys_Device* dev,
+ const Genesys_Sensor& sensor,
+ const ScanSession& session,
+ Genesys_Register_Set* reg,
+ const MotorProfile& motor_profile,
+ unsigned int exposure,
+ unsigned scan_yres,
+ unsigned int scan_lines,
+ unsigned int scan_dummy,
+ unsigned int feed_steps,
+ ScanFlag flags)
+{
+ DBG_HELPER_ARGS(dbg, "exposure=%d, scan_yres=%d, step_type=%d, scan_lines=%d, scan_dummy=%d, "
+ "feed_steps=%d, flags=%x",
+ exposure, scan_yres, static_cast<unsigned>(motor_profile.step_type),
+ scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
+
+ unsigned step_multiplier = 2;
+ bool use_fast_fed = false;
+
+ if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, ScanFlag::FEEDING))) {
+ use_fast_fed = true;
+ }
+ if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
+ use_fast_fed = false;
+ }
+
+ reg->set24(REG_LINCNT, scan_lines);
+
+ reg->set8(REG_0x02, 0);
+ sanei_genesys_set_motor_power(*reg, true);
+
+ std::uint8_t reg02 = reg->get8(REG_0x02);
+ if (use_fast_fed) {
+ reg02 |= REG_0x02_FASTFED;
+ } else {
+ reg02 &= ~REG_0x02_FASTFED;
+ }
+
+ // in case of automatic go home, move until home sensor
+ if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
+ reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
+ }
+
+ // disable backtracking if needed
+ if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) ||
+ (scan_yres >= 2400) ||
+ (scan_yres >= sensor.full_resolution))
+ {
+ reg02 |= REG_0x02_ACDCDIS;
+ }
+
+ if (has_flag(flags, ScanFlag::REVERSE)) {
+ reg02 |= REG_0x02_MTRREV;
+ } else {
+ reg02 &= ~REG_0x02_MTRREV;
+ }
+ reg->set8(REG_0x02, reg02);
+
+ // scan and backtracking slope table
+ auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres, exposure,
+ step_multiplier, motor_profile);
+
+ scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table);
+ scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table);
+ scanner_send_slope_table(dev, sensor, STOP_TABLE, scan_table.table);
+
+ reg->set8(REG_STEPNO, scan_table.table.size() / step_multiplier);
+ reg->set8(REG_FASTNO, scan_table.table.size() / step_multiplier);
+ reg->set8(REG_FSHDEC, scan_table.table.size() / step_multiplier);
+
+ // fast table
+ const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
+ if (fast_profile == nullptr) {
+ fast_profile = &motor_profile;
+ }
+
+ auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
+ *fast_profile);
+
+ scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table);
+ scanner_send_slope_table(dev, sensor, HOME_TABLE, fast_table.table);
+
+ reg->set8(REG_FMOVNO, fast_table.table.size() / step_multiplier);
+
+ if (motor_profile.motor_vref != -1 && fast_profile->motor_vref != 1) {
+ std::uint8_t vref = 0;
+ vref |= (motor_profile.motor_vref << REG_0x80S_TABLE1_NORMAL) & REG_0x80_TABLE1_NORMAL;
+ vref |= (motor_profile.motor_vref << REG_0x80S_TABLE2_BACK) & REG_0x80_TABLE2_BACK;
+ vref |= (fast_profile->motor_vref << REG_0x80S_TABLE4_FAST) & REG_0x80_TABLE4_FAST;
+ vref |= (fast_profile->motor_vref << REG_0x80S_TABLE5_GO_HOME) & REG_0x80_TABLE5_GO_HOME;
+ reg->set8(REG_0x80, vref);
+ }
+
+ // substract acceleration distance from feedl
+ unsigned feedl = feed_steps;
+ feedl <<= static_cast<unsigned>(motor_profile.step_type);
+
+ unsigned dist = scan_table.table.size() / step_multiplier;
+
+ if (use_fast_fed) {
+ dist += (fast_table.table.size() / step_multiplier) * 2;
+ }
+
+ // make sure when don't insane value : XXX STEF XXX in this case we should
+ // fall back to single table move
+ if (dist < feedl) {
+ feedl -= dist;
+ } else {
+ feedl = 1;
+ }
+
+ reg->set24(REG_FEEDL, feedl);
+
+ // doesn't seem to matter that much
+ std::uint32_t z1, z2;
+ sanei_genesys_calculate_zmod(use_fast_fed,
+ exposure,
+ scan_table.table,
+ scan_table.table.size() / step_multiplier,
+ feedl,
+ scan_table.table.size() / step_multiplier,
+ &z1,
+ &z2);
+ if (scan_yres > 600) {
+ z1 = 0;
+ z2 = 0;
+ }
+
+ reg->set24(REG_Z1MOD, z1);
+ reg->set24(REG_Z2MOD, z2);
+
+ reg->set8_mask(REG_0x1E, scan_dummy, 0x0f);
+
+ reg->set8_mask(REG_0x67, static_cast<unsigned>(motor_profile.step_type) << REG_0x67S_STEPSEL,
+ REG_0x67_STEPSEL);
+ reg->set8_mask(REG_0x68, static_cast<unsigned>(fast_profile->step_type) << REG_0x68S_FSTPSEL,
+ REG_0x68_FSTPSEL);
+
+ // steps for STOP table
+ reg->set8(REG_FMOVDEC, fast_table.table.size() / step_multiplier);
+}
+
+static void gl842_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set* reg, unsigned int exposure,
+ const ScanSession& session)
+{
+ DBG_HELPER(dbg);
+
+ scanner_setup_sensor(*dev, sensor, *reg);
+
+ dev->cmd_set->set_fe(dev, sensor, AFE_SET);
+
+ // enable shading
+ regs_set_optical_off(dev->model->asic_type, *reg);
+ if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
+ has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) ||
+ session.use_host_side_calib)
+ {
+ reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET;
+
+ } else {
+ reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET;
+ }
+
+ bool use_shdarea = true;
+
+ if (use_shdarea) {
+ reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA;
+ } else {
+ reg->find_reg(REG_0x01).value &= ~REG_0x01_SHDAREA;
+ }
+
+ if (dev->model->model_id == ModelId::CANON_8600F) {
+ reg->find_reg(REG_0x03).value |= REG_0x03_AVEENB;
+ } else {
+ reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB;
+ }
+
+ // FIXME: we probably don't need to set exposure to registers at this point. It was this way
+ // before a refactor.
+ sanei_genesys_set_lamp_power(dev, sensor, *reg,
+ !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
+
+ // select XPA
+ reg->find_reg(REG_0x03).value &= ~REG_0x03_XPASEL;
+ if (has_flag(session.params.flags, ScanFlag::USE_XPA)) {
+ reg->find_reg(REG_0x03).value |= REG_0x03_XPASEL;
+ }
+ reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA);
+
+ // BW threshold
+ reg->set8(REG_0x2E, 0x7f);
+ reg->set8(REG_0x2F, 0x7f);
+
+ // monochrome / color scan parameters
+ std::uint8_t reg04 = reg->get8(REG_0x04);
+ reg04 = reg04 & REG_0x04_FESET;
+
+ switch (session.params.depth) {
+ case 8:
+ break;
+ case 16:
+ reg04 |= REG_0x04_BITSET;
+ break;
+ }
+
+ if (session.params.channels == 1) {
+ switch (session.params.color_filter) {
+ case ColorFilter::RED: reg04 |= 0x14; break;
+ case ColorFilter::BLUE: reg04 |= 0x1c; break;
+ case ColorFilter::GREEN: reg04 |= 0x18; break;
+ default:
+ break; // should not happen
+ }
+ } else {
+ switch (dev->frontend.layout.type) {
+ case FrontendType::WOLFSON:
+ // pixel by pixel
+ reg04 |= 0x10;
+ break;
+ case FrontendType::ANALOG_DEVICES:
+ // slow color pixel by pixel
+ reg04 |= 0x20;
+ break;
+ default:
+ throw SaneException("Invalid frontend type %d",
+ static_cast<unsigned>(dev->frontend.layout.type));
+ }
+ }
+
+ reg->set8(REG_0x04, reg04);
+
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution,
+ session.params.channels,
+ session.params.scan_method);
+ sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw);
+
+ if (should_enable_gamma(session, sensor)) {
+ reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
+ } else {
+ reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB;
+ }
+
+ reg->set16(REG_DPISET, sensor.register_dpiset);
+
+ reg->set16(REG_STRPIXEL, session.pixel_startx);
+ reg->set16(REG_ENDPIXEL, session.pixel_endx);
+
+ if (dev->model->is_cis) {
+ reg->set24(REG_MAXWD, session.output_line_bytes_raw * session.params.channels);
+ } else {
+ reg->set24(REG_MAXWD, session.output_line_bytes_raw);
+ }
+
+ unsigned tgtime = exposure / 65536 + 1;
+ reg->set16(REG_LPERIOD, exposure / tgtime);
+
+ reg->set8(REG_DUMMY, sensor.dummy_pixel);
+}
+
+void CommandSetGl842::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set* reg,
+ const ScanSession& session) const
+{
+ DBG_HELPER(dbg);
+ session.assert_computed();
+
+ // we enable true gray for cis scanners only, and just when doing scan since color calibration
+ // is OK for this mode
+
+ int dummy = 0;
+
+ /* slope_dpi */
+ /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */
+ int slope_dpi = 0;
+ if (dev->model->is_cis) {
+ slope_dpi = session.params.yres * session.params.channels;
+ } else {
+ slope_dpi = session.params.yres;
+ }
+ slope_dpi = slope_dpi * (1 + dummy);
+
+ int exposure = sensor.exposure_lperiod;
+ if (exposure < 0) {
+ throw std::runtime_error("Exposure not defined in sensor definition");
+ }
+ if (dev->model->model_id == ModelId::CANON_LIDE_90) {
+ exposure *= 2;
+ }
+ const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure, session);
+
+ // now _LOGICAL_ optical values used are known, setup registers
+ gl842_init_optical_regs_scan(dev, sensor, reg, exposure, session);
+ gl842_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure, slope_dpi,
+ session.optical_line_count, dummy, session.params.starty,
+ session.params.flags);
+
+ setup_image_pipeline(*dev, session);
+
+ dev->read_active = true;
+
+ dev->session = session;
+
+ dev->total_bytes_read = 0;
+ dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines;
+}
+
+ScanSession CommandSetGl842::calculate_scan_session(const Genesys_Device* dev,
+ const Genesys_Sensor& sensor,
+ const Genesys_Settings& settings) const
+{
+ DBG_HELPER(dbg);
+ debug_dump(DBG_info, settings);
+
+ ScanFlag flags = ScanFlag::NONE;
+
+ float move = 0.0f;
+ if (settings.scan_method == ScanMethod::TRANSPARENCY ||
+ settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ // note: scanner_move_to_ta() function has already been called and the sensor is at the
+ // transparency adapter
+ if (!dev->ignore_offsets) {
+ move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta;
+ }
+ flags |= ScanFlag::USE_XPA;
+ } else {
+ if (!dev->ignore_offsets) {
+ move = dev->model->y_offset;
+ }
+ }
+
+ move += settings.tl_y;
+
+ int move_dpi = dev->motor.base_ydpi;
+ move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
+
+ float start = 0.0f;
+ if (settings.scan_method==ScanMethod::TRANSPARENCY ||
+ settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ start = dev->model->x_offset_ta;
+ } else {
+ start = dev->model->x_offset;
+ }
+ start = start + settings.tl_x;
+
+ start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
+
+ ScanSession session;
+ session.params.xres = settings.xres;
+ session.params.yres = settings.yres;
+ session.params.startx = static_cast<unsigned>(start);
+ session.params.starty = static_cast<unsigned>(move);
+ session.params.pixels = settings.pixels;
+ session.params.requested_pixels = settings.requested_pixels;
+ session.params.lines = settings.lines;
+ session.params.depth = settings.depth;
+ session.params.channels = settings.get_channels();
+ session.params.scan_method = settings.scan_method;
+ session.params.scan_mode = settings.scan_mode;
+ session.params.color_filter = settings.color_filter;
+ session.params.flags = flags;
+ compute_session(dev, session, sensor);
+
+ return session;
+}
+
+void CommandSetGl842::save_power(Genesys_Device* dev, bool enable) const
+{
+ (void) dev;
+ DBG_HELPER_ARGS(dbg, "enable = %d", enable);
+}
+
+void CommandSetGl842::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const
+{
+ (void) dev;
+ DBG_HELPER_ARGS(dbg, "delay = %d", delay);
+}
+
+void CommandSetGl842::eject_document(Genesys_Device* dev) const
+{
+ (void) dev;
+ DBG_HELPER(dbg);
+}
+
+
+void CommandSetGl842::load_document(Genesys_Device* dev) const
+{
+ DBG_HELPER(dbg);
+ (void) dev;
+}
+
+void CommandSetGl842::detect_document_end(Genesys_Device* dev) const
+{
+ DBG_HELPER(dbg);
+ (void) dev;
+ throw SaneException(SANE_STATUS_UNSUPPORTED);
+}
+
+// Send the low-level scan command
+void CommandSetGl842::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set* reg, bool start_motor) const
+{
+ DBG_HELPER(dbg);
+ (void) sensor;
+
+ if (reg->state.is_xpa_on && reg->state.is_lamp_on &&
+ !has_flag(dev->model->flags, ModelFlag::TA_NO_SECONDARY_LAMP))
+ {
+ dev->cmd_set->set_xpa_lamp_power(*dev, true);
+ }
+ if (reg->state.is_xpa_on && !has_flag(dev->model->flags, ModelFlag::UTA_NO_SECONDARY_MOTOR)) {
+ dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY);
+ }
+
+ if (dev->model->model_id == ModelId::CANON_LIDE_90) {
+ if (has_flag(dev->session.params.flags, ScanFlag::REVERSE)) {
+ dev->interface->write_register(REG_0x6B, 0x01);
+ dev->interface->write_register(REG_0x6C, 0x02);
+ } else {
+ dev->interface->write_register(REG_0x6B, 0x03);
+ switch (dev->session.params.xres) {
+ case 150: dev->interface->write_register(REG_0x6C, 0x74); break;
+ case 300: dev->interface->write_register(REG_0x6C, 0x38); break;
+ case 600: dev->interface->write_register(REG_0x6C, 0x1c); break;
+ case 1200: dev->interface->write_register(REG_0x6C, 0x2c); break;
+ case 2400: dev->interface->write_register(REG_0x6C, 0x0c); break;
+ default:
+ break;
+ }
+ }
+ dev->interface->sleep_ms(100);
+ }
+
+ scanner_clear_scan_and_feed_counts(*dev);
+
+ // enable scan and motor
+ std::uint8_t val = dev->interface->read_register(REG_0x01);
+ val |= REG_0x01_SCAN;
+ dev->interface->write_register(REG_0x01, val);
+
+ scanner_start_action(*dev, start_motor);
+
+ switch (reg->state.motor_mode) {
+ case MotorMode::PRIMARY: {
+ if (reg->state.is_motor_on) {
+ dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
+ }
+ break;
+ }
+ case MotorMode::PRIMARY_AND_SECONDARY: {
+ if (reg->state.is_motor_on) {
+ dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
+ dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
+ }
+ break;
+ }
+ case MotorMode::SECONDARY: {
+ if (reg->state.is_motor_on) {
+ dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
+ }
+ break;
+ }
+ }
+}
+
+void CommandSetGl842::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg,
+ bool check_stop) const
+{
+ DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop);
+
+ if (reg->state.is_xpa_on) {
+ dev->cmd_set->set_xpa_lamp_power(*dev, false);
+ }
+
+ if (!dev->model->is_sheetfed) {
+ scanner_stop_action(*dev);
+ }
+}
+
+void CommandSetGl842::move_back_home(Genesys_Device* dev, bool wait_until_home) const
+{
+ scanner_move_back_home(*dev, wait_until_home);
+}
+
+void CommandSetGl842::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs) const
+{
+ DBG_HELPER(dbg);
+ int move;
+
+ float calib_size_mm = 0;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ calib_size_mm = dev->model->y_size_calib_ta_mm;
+ } else {
+ calib_size_mm = dev->model->y_size_calib_mm;
+ }
+
+ unsigned resolution = sensor.shading_resolution;
+
+ unsigned channels = 3;
+ const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
+ dev->settings.scan_method);
+
+ unsigned calib_pixels = 0;
+ unsigned calib_pixels_offset = 0;
+
+ if (should_calibrate_only_active_area(*dev, dev->settings)) {
+ float offset = dev->model->x_offset_ta;
+ // FIXME: we should use resolution here
+ offset = static_cast<float>((offset * dev->settings.xres) / MM_PER_INCH);
+
+ float size = dev->model->x_size_ta;
+ size = static_cast<float>((size * dev->settings.xres) / MM_PER_INCH);
+
+ calib_pixels_offset = static_cast<std::size_t>(offset);
+ calib_pixels = static_cast<std::size_t>(size);
+ } else {
+ calib_pixels_offset = 0;
+ calib_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
+ }
+
+ ScanFlag flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA |
+ ScanFlag::DISABLE_BUFFER_FULL_MOVE;
+
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ // note: scanner_move_to_ta() function has already been called and the sensor is at the
+ // transparency adapter
+ move = static_cast<int>(dev->model->y_offset_calib_white_ta -
+ dev->model->y_offset_sensor_to_ta);
+ flags |= ScanFlag::USE_XPA;
+ } else {
+ move = static_cast<int>(dev->model->y_offset_calib_white);
+ }
+
+ move = static_cast<int>((move * resolution) / MM_PER_INCH);
+ unsigned calib_lines = static_cast<unsigned>(calib_size_mm * resolution / MM_PER_INCH);
+
+ ScanSession session;
+ session.params.xres = resolution;
+ session.params.yres = resolution;
+ session.params.startx = calib_pixels_offset;
+ session.params.starty = move;
+ session.params.pixels = calib_pixels;
+ session.params.lines = calib_lines;
+ session.params.depth = 16;
+ session.params.channels = channels;
+ session.params.scan_method = dev->settings.scan_method;
+ session.params.scan_mode = dev->settings.scan_mode;
+ session.params.color_filter = dev->settings.color_filter;
+ session.params.flags = flags;
+ compute_session(dev, session, calib_sensor);
+
+ init_regs_for_scan_session(dev, calib_sensor, &regs, session);
+
+ dev->calib_session = session;
+}
+
+void CommandSetGl842::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const
+{
+ DBG_HELPER(dbg);
+
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200)
+ return; // No gamma on this model
+
+ unsigned size = 256;
+
+ std::vector<uint8_t> gamma(size * 2 * 3);
+
+ std::vector<uint16_t> rgamma = get_gamma_table(dev, sensor, GENESYS_RED);
+ std::vector<uint16_t> ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN);
+ std::vector<uint16_t> bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE);
+
+ // copy sensor specific's gamma tables
+ for (unsigned i = 0; i < size; i++) {
+ gamma[i * 2 + size * 0 + 0] = rgamma[i] & 0xff;
+ gamma[i * 2 + size * 0 + 1] = (rgamma[i] >> 8) & 0xff;
+ gamma[i * 2 + size * 2 + 0] = ggamma[i] & 0xff;
+ gamma[i * 2 + size * 2 + 1] = (ggamma[i] >> 8) & 0xff;
+ gamma[i * 2 + size * 4 + 0] = bgamma[i] & 0xff;
+ gamma[i * 2 + size * 4 + 1] = (bgamma[i] >> 8) & 0xff;
+ }
+
+ dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3);
+}
+
+SensorExposure CommandSetGl842::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs) const
+{
+ return scanner_led_calibration(*dev, sensor, regs);
+}
+
+void CommandSetGl842::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs) const
+{
+ scanner_offset_calibration(*dev, sensor, regs);
+}
+
+void CommandSetGl842::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs, int dpi) const
+{
+ scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
+}
+
+void CommandSetGl842::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set* reg) const
+{
+ DBG_HELPER(dbg);
+ (void) sensor;
+
+ unsigned channels = 3;
+ unsigned resolution = dev->model->get_resolution_settings(dev->settings.scan_method)
+ .get_nearest_resolution_x(600);
+
+ const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
+ dev->settings.scan_method);
+ unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH / 2;
+
+ *reg = dev->reg;
+
+ auto flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA |
+ ScanFlag::SINGLE_LINE |
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ flags |= ScanFlag::USE_XPA;
+ }
+
+ ScanSession session;
+ session.params.xres = resolution;
+ session.params.yres = resolution;
+ session.params.startx = (num_pixels / 2) * resolution / calib_sensor.full_resolution;
+ session.params.starty = 0;
+ session.params.pixels = num_pixels;
+ session.params.lines = 1;
+ session.params.depth = dev->model->bpp_color_values.front();
+ session.params.channels = channels;
+ session.params.scan_method = dev->settings.scan_method;
+ session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
+ session.params.color_filter = dev->settings.color_filter;
+ session.params.flags = flags;
+
+ compute_session(dev, session, calib_sensor);
+
+ init_regs_for_scan_session(dev, calib_sensor, reg, session);
+
+ sanei_genesys_set_motor_power(*reg, false);
+}
+
+static void gl842_init_gpio(Genesys_Device* dev)
+{
+ DBG_HELPER(dbg);
+ apply_registers_ordered(dev->gpo.regs, { 0x6e, 0x6f }, [&](const GenesysRegisterSetting& reg)
+ {
+ dev->interface->write_register(reg.address, reg.value);
+ });
+}
+
+void CommandSetGl842::asic_boot(Genesys_Device* dev, bool cold) const
+{
+ DBG_HELPER(dbg);
+
+ if (cold) {
+ dev->interface->write_register(0x0e, 0x01);
+ dev->interface->write_register(0x0e, 0x00);
+ }
+
+ // setup initial register values
+ gl842_init_registers(*dev);
+ dev->interface->write_registers(dev->reg);
+
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
+ uint8_t data[32] = {
+ 0xd0, 0x38, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6a, 0x73, 0x63, 0x68, 0x69, 0x65, 0x6e, 0x00,
+ };
+
+ dev->interface->write_buffer(0x3c, 0x010a00, data, 32);
+ }
+
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
+ dev->interface->write_0x8c(0x10, 0x94);
+ }
+ if (dev->model->model_id == ModelId::CANON_LIDE_90) {
+ dev->interface->write_0x8c(0x10, 0xd4);
+ }
+
+ // set RAM read address
+ dev->interface->write_register(REG_0x2A, 0x00);
+ dev->interface->write_register(REG_0x2B, 0x00);
+
+ // setup gpio
+ gl842_init_gpio(dev);
+ dev->interface->sleep_ms(100);
+}
+
+void CommandSetGl842::init(Genesys_Device* dev) const
+{
+ DBG_INIT();
+ DBG_HELPER(dbg);
+
+ sanei_genesys_asic_init(dev);
+}
+
+void CommandSetGl842::update_hardware_sensors(Genesys_Scanner* s) const
+{
+ DBG_HELPER(dbg);
+ (void) s;
+}
+
+void CommandSetGl842::update_home_sensor_gpio(Genesys_Device& dev) const
+{
+ DBG_HELPER(dbg);
+ if (dev.model->model_id == ModelId::CANON_LIDE_90) {
+ std::uint8_t val = dev.interface->read_register(REG_0x6C);
+ val |= 0x02;
+ dev.interface->write_register(REG_0x6C, val);
+ }
+}
+
+/**
+ * Send shading calibration data. The buffer is considered to always hold values
+ * for all the channels.
+ */
+void CommandSetGl842::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ uint8_t* data, int size) const
+{
+ DBG_HELPER(dbg);
+
+ int offset = 0;
+ unsigned length = size;
+
+ if (dev->reg.get8(REG_0x01) & REG_0x01_SHDAREA) {
+ offset = dev->session.params.startx * sensor.shading_resolution /
+ dev->session.params.xres;
+
+ length = dev->session.output_pixels * sensor.shading_resolution /
+ dev->session.params.xres;
+
+ offset += sensor.shading_pixel_offset;
+
+ // 16 bit words, 2 words per color, 3 color channels
+ length *= 2 * 2 * 3;
+ offset *= 2 * 2 * 3;
+ } else {
+ offset += sensor.shading_pixel_offset * 2 * 2 * 3;
+ }
+
+ dev->interface->record_key_value("shading_offset", std::to_string(offset));
+ dev->interface->record_key_value("shading_length", std::to_string(length));
+
+ std::vector<uint8_t> final_data(length, 0);
+
+ unsigned count = 0;
+ if (offset < 0) {
+ count += (-offset);
+ length -= (-offset);
+ offset = 0;
+ }
+ if (static_cast<int>(length) + offset > static_cast<int>(size)) {
+ length = size - offset;
+ }
+
+ for (unsigned i = 0; i < length; i++) {
+ final_data[count++] = data[offset + i];
+ count++;
+ }
+
+ dev->interface->write_buffer(0x3c, 0, final_data.data(), count);
+}
+
+bool CommandSetGl842::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
+{
+ (void) dev;
+ return true;
+}
+
+void CommandSetGl842::wait_for_motor_stop(Genesys_Device* dev) const
+{
+ (void) dev;
+}
+
+} // namespace gl842
+} // namespace genesys
diff --git a/backend/genesys/gl842.h b/backend/genesys/gl842.h
new file mode 100644
index 0000000..288d29c
--- /dev/null
+++ b/backend/genesys/gl842.h
@@ -0,0 +1,128 @@
+/* sane - Scanner Access Now Easy.
+
+ Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr>
+
+ This file is part of the SANE package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ As a special exception, the authors of SANE give permission for
+ additional uses of the libraries contained in this release of SANE.
+
+ The exception is that, if you link a SANE library with other files
+ to produce an executable, this does not by itself cause the
+ resulting executable to be covered by the GNU General Public
+ License. Your use of that executable is in no way restricted on
+ account of linking the SANE library code into it.
+
+ This exception does not, however, invalidate any other reasons why
+ the executable file might be covered by the GNU General Public
+ License.
+
+ If you submit changes to SANE to the maintainers to be included in
+ a subsequent release, you agree by submitting the changes that
+ those changes may be distributed with this exception intact.
+
+ If you write modifications of your own for SANE, it is your choice
+ whether to permit this exception to apply to your modifications.
+ If you do not wish that, delete this exception notice.
+*/
+
+#include "genesys.h"
+#include "command_set_common.h"
+
+#ifndef BACKEND_GENESYS_GL842_H
+#define BACKEND_GENESYS_GL842_H
+
+namespace genesys {
+namespace gl842 {
+
+class CommandSetGl842 : public CommandSetCommon
+{
+public:
+ ~CommandSetGl842() override = default;
+
+ bool needs_home_before_init_regs_for_scan(Genesys_Device* dev) const override;
+
+ void init(Genesys_Device* dev) const override;
+
+ void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set* regs) const override;
+
+ void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs) const override;
+
+ void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set* reg,
+ const ScanSession& session) const override;
+
+ void set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const override;
+ void set_powersaving(Genesys_Device* dev, int delay) const override;
+ void save_power(Genesys_Device* dev, bool enable) const override;
+
+ void begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set* regs, bool start_motor) const override;
+
+ void end_scan(Genesys_Device* dev, Genesys_Register_Set* regs, bool check_stop) const override;
+
+ void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override;
+
+ void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs) const override;
+
+ void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs, int dpi) const override;
+
+ SensorExposure led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set& regs) const override;
+
+ void wait_for_motor_stop(Genesys_Device* dev) const override;
+
+ void move_back_home(Genesys_Device* dev, bool wait_until_home) const override;
+
+ void update_hardware_sensors(struct Genesys_Scanner* s) const override;
+
+ void 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 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
diff --git a/backend/genesys/gl842_registers.h b/backend/genesys/gl842_registers.h
new file mode 100644
index 0000000..b6934ce
--- /dev/null
+++ b/backend/genesys/gl842_registers.h
@@ -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
diff --git a/backend/genesys/gl843.cpp b/backend/genesys/gl843.cpp
index f83ac8d..8233bde 100644
--- a/backend/genesys/gl843.cpp
+++ b/backend/genesys/gl843.cpp
@@ -54,60 +54,18 @@
namespace genesys {
namespace gl843 {
-// Set address for writing data
-static void gl843_set_buffer_address(Genesys_Device* dev, uint32_t addr)
-{
- DBG_HELPER_ARGS(dbg, "setting address to 0x%05x", addr & 0xffff);
-
- dev->interface->write_register(0x5b, ((addr >> 8) & 0xff));
- dev->interface->write_register(0x5c, (addr & 0xff));
-}
-
/**
* compute the step multiplier used
*/
static int gl843_get_step_multiplier(Genesys_Register_Set* regs)
{
- GenesysRegister *r = sanei_genesys_get_address(regs, REG_0x9D);
- int value = 1;
- if (r != nullptr)
- {
- switch (r->value & 0x0c)
- {
- case 0x04:
- value = 2;
- break;
- case 0x08:
- value = 4;
- break;
- default:
- value = 1;
- }
- }
- DBG(DBG_io, "%s: step multiplier is %d\n", __func__, value);
- return value;
-}
-
-/** copy sensor specific settings */
-static void gl843_setup_sensor(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs)
-{
- DBG_HELPER(dbg);
- for (const auto& custom_reg : sensor.custom_regs) {
- regs->set8(custom_reg.address, custom_reg.value);
+ switch (regs->get8(REG_0x9D) & 0x0c) {
+ case 0x04: return 2;
+ case 0x08: return 4;
+ default: return 1;
}
- if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE) &&
- dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7200I &&
- dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7300 &&
- dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7500I)
- {
- regs->set8(0x7d, 0x90);
- }
-
- dev->segment_order = sensor.segment_order;
}
-
/** @brief set all registers to default values .
* This function is called only once at the beginning and
* fills register startup values for registers reused across scans.
@@ -118,9 +76,9 @@ static void gl843_setup_sensor(Genesys_Device* dev, const Genesys_Sensor& sensor
static void
gl843_init_registers (Genesys_Device * dev)
{
- // Within this function SENSOR_DEF marker documents that a register is part
- // of the sensors definition and the actual value is set in
- // gl843_setup_sensor().
+ // Within this function SENSOR_DEF marker documents that a register is part
+ // of the sensors definition and the actual value is set in
+ // scanner_setup_sensor().
// 0x6c, 0x6d, 0x6e, 0x6f, 0xa6, 0xa7, 0xa8, 0xa9 are defined in the Gpo sensor struct
@@ -158,8 +116,16 @@ gl843_init_registers (Genesys_Device * dev)
dev->reg.init_reg(0x05, 0x08);
}
+ auto initial_scan_method = dev->model->default_method;
+ if (dev->model->model_id == ModelId::CANON_4400F ||
+ dev->model->model_id == ModelId::CANON_8600F)
+ {
+ initial_scan_method = ScanMethod::TRANSPARENCY;
+ }
const auto& sensor = sanei_genesys_find_sensor_any(dev);
- sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res);
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, sensor.full_resolution,
+ 3, initial_scan_method);
+ sanei_genesys_set_dpihw(dev->reg, dpihw_sensor.register_dpihw);
// TODO: on 8600F the windows driver turns off GAIN4 which is recommended
dev->reg.init_reg(0x06, 0xd8); /* SCANMOD=110, PWRBIT and GAIN4 */
@@ -402,11 +368,11 @@ gl843_init_registers (Genesys_Device * dev)
// STEPSEL[0:1]. Motor movement step mode selection for tables 1-3 in
// scanning mode.
// MTRPWM[0:5]. Motor phase PWM duty cycle setting for tables 1-3
- dev->reg.init_reg(0x67, 0x7f);
+ dev->reg.init_reg(0x67, 0x7f); // MOTOR_PROFILE
// FSTPSEL[0:1]: Motor movement step mode selection for tables 4-5 in
// command mode.
// FASTPWM[5:0]: Motor phase PWM duty cycle setting for tables 4-5
- dev->reg.init_reg(0x68, 0x7f);
+ dev->reg.init_reg(0x68, 0x7f); // MOTOR_PROFILE
if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300) {
dev->reg.init_reg(0x67, 0x80);
@@ -415,17 +381,11 @@ gl843_init_registers (Genesys_Device * dev)
// FSHDEC[0:7]: The number of deceleration steps after scanning is finished
// (table 3)
- dev->reg.init_reg(0x69, 0x01);
- if (dev->model->model_id == ModelId::CANON_8600F) {
- dev->reg.init_reg(0x69, 64);
- }
+ dev->reg.init_reg(0x69, 0x01); // MOTOR_PROFILE
// FMOVNO[0:7] The number of acceleration or deceleration steps for fast
// moving (table 4)
- dev->reg.init_reg(0x6a, 0x04);
- if (dev->model->model_id == ModelId::CANON_8600F) {
- dev->reg.init_reg(0x69, 64);
- }
+ dev->reg.init_reg(0x6a, 0x04); // MOTOR_PROFILE
// GPIO-related register bits
dev->reg.init_reg(0x6b, 0x30);
@@ -516,7 +476,7 @@ gl843_init_registers (Genesys_Device * dev)
// VRHOME, VRMOVE, VRBACK, VRSCAN: Vref settings of the motor driver IC for
// moving in various situations.
- dev->reg.init_reg(0x80, 0x00);
+ dev->reg.init_reg(0x80, 0x00); // MOTOR_PROFILE
if (dev->model->model_id == ModelId::CANON_4400F) {
dev->reg.init_reg(0x80, 0x0c);
}
@@ -632,7 +592,7 @@ gl843_init_registers (Genesys_Device * dev)
dev->reg.init_reg(0xaa, 0x00);
}
- // GPOM9, MULSTOP[0-2], NODECEL, TB3TB1, TB5TB2, FIX16CLK. Not documented
+ // GPOM9, MULSTOP[0-2], NODECEL, TB3TB1, TB5TB2, FIX16CLK.
if (dev->model->model_id != ModelId::CANON_8400F &&
dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7200I &&
dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7300) {
@@ -643,10 +603,9 @@ gl843_init_registers (Genesys_Device * dev)
}
if (dev->model->model_id == ModelId::HP_SCANJET_G4010 ||
dev->model->model_id == ModelId::HP_SCANJET_G4050 ||
+ dev->model->model_id == ModelId::CANON_8600F ||
dev->model->model_id == ModelId::HP_SCANJET_4850C)
{
- // BUG: this should apply to ModelId::CANON_CANOSCAN_8600F too, but due to previous bug
- // the 8400F case overwrote it
dev->reg.init_reg(0xab, 0x40);
}
@@ -660,8 +619,6 @@ gl843_init_registers (Genesys_Device * dev)
dev->reg.init_reg(0xac, 0x00);
}
- dev->calib_reg = dev->reg;
-
if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I) {
uint8_t data[32] = {
0x8c, 0x8f, 0xc9, 0x00, 0x01, 0x00, 0x00, 0x00,
@@ -670,48 +627,8 @@ gl843_init_registers (Genesys_Device * dev)
0x6a, 0x73, 0x63, 0x68, 0x69, 0x65, 0x6e, 0x00,
};
- dev->interface->write_buffer(0x3c, 0x3ff000, data, 32,
- ScannerInterface::FLAG_SWAP_REGISTERS);
- }
-}
-
-// Send slope table for motor movement slope_table in machine byte order
-static void gl843_send_slope_table(Genesys_Device* dev, int table_nr,
- const std::vector<uint16_t>& slope_table,
- int steps)
-{
- DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps);
-
- int i;
- char msg[10000];
-
- std::vector<uint8_t> table(steps * 2);
- for (i = 0; i < steps; i++)
- {
- table[i * 2] = slope_table[i] & 0xff;
- table[i * 2 + 1] = slope_table[i] >> 8;
- }
-
- if (DBG_LEVEL >= DBG_io)
- {
- std::sprintf(msg, "write slope %d (%d)=", table_nr, steps);
- for (i = 0; i < steps; i++) {
- std::sprintf (msg+strlen(msg), "%d", slope_table[i]);
- }
- DBG(DBG_io, "%s: %s\n", __func__, msg);
- }
-
- if (dev->interface->is_mock()) {
- dev->interface->record_slope_table(table_nr, slope_table);
+ dev->interface->write_buffer(0x3c, 0x3ff000, data, 32);
}
-
- // slope table addresses are fixed : 0x40000, 0x48000, 0x50000, 0x58000, 0x60000
- // XXX STEF XXX USB 1.1 ? sanei_genesys_write_0x8c (dev, 0x0f, 0x14);
- dev->interface->write_gamma(0x28, 0x40000 + 0x8000 * table_nr, table.data(), steps * 2,
- ScannerInterface::FLAG_SWAP_REGISTERS);
-
- // FIXME: remove this when updating tests
- gl843_set_buffer_address(dev, 0);
}
static void gl843_set_ad_fe(Genesys_Device* dev)
@@ -728,14 +645,9 @@ void CommandSetGl843::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
set == AFE_SET ? "set" :
set == AFE_POWER_SAVE ? "powersave" : "huh?");
(void) sensor;
- int i;
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s(): setting DAC %u\n", __func__,
- static_cast<unsigned>(dev->model->adc_id));
- dev->frontend = dev->frontend_initial;
- dev->frontend_is_init = true;
+ if (set == AFE_INIT) {
+ dev->frontend = dev->frontend_initial;
}
// check analog frontend type
@@ -749,153 +661,135 @@ void CommandSetGl843::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
throw SaneException(SANE_STATUS_UNSUPPORTED, "unsupported frontend type %d", fe_type);
}
- DBG(DBG_proc, "%s(): frontend reset complete\n", __func__);
-
- for (i = 1; i <= 3; i++)
- {
- // FIXME: the check below is just historical artifact, we can remove it when convenient
- if (!dev->frontend_is_init) {
- dev->interface->write_fe_register(i, 0x00);
- } else {
- dev->interface->write_fe_register(i, dev->frontend.regs.get_value(0x00 + i));
- }
+ for (unsigned i = 1; i <= 3; i++) {
+ dev->interface->write_fe_register(i, dev->frontend.regs.get_value(0x00 + i));
}
for (const auto& reg : sensor.custom_fe_regs) {
dev->interface->write_fe_register(reg.address, reg.value);
}
- for (i = 0; i < 3; i++)
- {
- // FIXME: the check below is just historical artifact, we can remove it when convenient
- if (!dev->frontend_is_init) {
- dev->interface->write_fe_register(0x20 + i, 0x00);
- } else {
- dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i));
- }
+ for (unsigned i = 0; i < 3; i++) {
+ dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i));
}
if (dev->model->sensor_id == SensorId::CCD_KVSS080) {
- for (i = 0; i < 3; i++)
- {
- // FIXME: the check below is just historical artifact, we can remove it when convenient
- if (!dev->frontend_is_init) {
- dev->interface->write_fe_register(0x24 + i, 0x00);
- } else {
- dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i));
- }
- }
+ for (unsigned i = 0; i < 3; i++) {
+ dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i));
+ }
}
- for (i = 0; i < 3; i++)
- {
- // FIXME: the check below is just historical artifact, we can remove it when convenient
- if (!dev->frontend_is_init) {
- dev->interface->write_fe_register(0x28 + i, 0x00);
- } else {
- dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i));
- }
+ for (unsigned i = 0; i < 3; i++) {
+ dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i));
}
}
-
static void gl843_init_motor_regs_scan(Genesys_Device* dev,
const Genesys_Sensor& sensor,
+ const ScanSession& session,
Genesys_Register_Set* reg,
- const Motor_Profile& motor_profile,
+ const MotorProfile& motor_profile,
unsigned int exposure,
unsigned scan_yres,
unsigned int scan_lines,
unsigned int scan_dummy,
unsigned int feed_steps,
- MotorFlag flags)
+ ScanFlag flags)
{
DBG_HELPER_ARGS(dbg, "exposure=%d, scan_yres=%d, step_type=%d, scan_lines=%d, scan_dummy=%d, "
"feed_steps=%d, flags=%x",
exposure, scan_yres, static_cast<unsigned>(motor_profile.step_type),
scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
- int use_fast_fed, coeff;
- unsigned int lincnt;
unsigned feedl, dist;
- GenesysRegister *r;
- uint32_t z1, z2;
/* get step multiplier */
unsigned step_multiplier = gl843_get_step_multiplier (reg);
- use_fast_fed = 0;
+ bool use_fast_fed = false;
- if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, MotorFlag::FEED))) {
- use_fast_fed = 1;
+ if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, ScanFlag::FEEDING))) {
+ use_fast_fed = true;
+ }
+ if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
+ use_fast_fed = false;
}
- lincnt=scan_lines;
- reg->set24(REG_LINCNT, lincnt);
- DBG(DBG_io, "%s: lincnt=%d\n", __func__, lincnt);
+ reg->set24(REG_LINCNT, scan_lines);
- /* compute register 02 value */
- r = sanei_genesys_get_address(reg, REG_0x02);
- r->value = 0x00;
- sanei_genesys_set_motor_power(*reg, true);
+ reg->set8(REG_0x02, 0);
+ sanei_genesys_set_motor_power(*reg, true);
+ std::uint8_t reg02 = reg->get8(REG_0x02);
if (use_fast_fed) {
- r->value |= REG_0x02_FASTFED;
+ reg02 |= REG_0x02_FASTFED;
} else {
- r->value &= ~REG_0x02_FASTFED;
+ reg02 &= ~REG_0x02_FASTFED;
}
- /* in case of automatic go home, move until home sensor */
- if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) {
- r->value |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
+ // in case of automatic go home, move until home sensor
+ if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
+ reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
}
/* disable backtracking */
- if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE)
- ||(scan_yres>=2400 && dev->model->model_id != ModelId::CANON_4400F)
- ||(scan_yres>=sensor.optical_res))
+ if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) ||
+ (scan_yres>=2400 && dev->model->model_id != ModelId::CANON_4400F) ||
+ (scan_yres>=sensor.full_resolution))
{
- r->value |= REG_0x02_ACDCDIS;
+ reg02 |= REG_0x02_ACDCDIS;
}
- if (has_flag(flags, MotorFlag::REVERSE)) {
- r->value |= REG_0x02_MTRREV;
+ if (has_flag(flags, ScanFlag::REVERSE)) {
+ reg02 |= REG_0x02_MTRREV;
} else {
- r->value &= ~REG_0x02_MTRREV;
+ reg02 &= ~REG_0x02_MTRREV;
}
+ reg->set8(REG_0x02, reg02);
- /* scan and backtracking slope table */
- auto scan_table = sanei_genesys_slope_table(dev->model->asic_type, scan_yres, exposure,
- dev->motor.base_ydpi, step_multiplier,
- motor_profile);
+ // scan and backtracking slope table
+ auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres, exposure,
+ step_multiplier, motor_profile);
- gl843_send_slope_table(dev, SCAN_TABLE, scan_table.table, scan_table.steps_count);
- gl843_send_slope_table(dev, BACKTRACK_TABLE, scan_table.table, scan_table.steps_count);
+ scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table);
+ scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table);
+ scanner_send_slope_table(dev, sensor, STOP_TABLE, scan_table.table);
- reg->set8(REG_STEPNO, scan_table.steps_count / step_multiplier);
- reg->set8(REG_FASTNO, scan_table.steps_count / step_multiplier);
+ reg->set8(REG_STEPNO, scan_table.table.size() / step_multiplier);
+ reg->set8(REG_FASTNO, scan_table.table.size() / step_multiplier);
+ reg->set8(REG_FSHDEC, scan_table.table.size() / step_multiplier);
// fast table
- unsigned fast_yres = sanei_genesys_get_lowest_ydpi(dev);
- auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_yres, exposure,
- dev->motor.base_ydpi, step_multiplier,
- motor_profile);
- gl843_send_slope_table(dev, STOP_TABLE, fast_table.table, fast_table.steps_count);
- gl843_send_slope_table(dev, FAST_TABLE, fast_table.table, fast_table.steps_count);
- gl843_send_slope_table(dev, HOME_TABLE, fast_table.table, fast_table.steps_count);
+ const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
+ if (fast_profile == nullptr) {
+ fast_profile = &motor_profile;
+ }
- reg->set8(REG_FSHDEC, fast_table.steps_count / step_multiplier);
- reg->set8(REG_FMOVNO, fast_table.steps_count / step_multiplier);
+ auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
+ *fast_profile);
+
+ scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table);
+ scanner_send_slope_table(dev, sensor, HOME_TABLE, fast_table.table);
+
+ reg->set8(REG_FMOVNO, fast_table.table.size() / step_multiplier);
+
+ if (motor_profile.motor_vref != -1 && fast_profile->motor_vref != 1) {
+ std::uint8_t vref = 0;
+ vref |= (motor_profile.motor_vref << REG_0x80S_TABLE1_NORMAL) & REG_0x80_TABLE1_NORMAL;
+ vref |= (motor_profile.motor_vref << REG_0x80S_TABLE2_BACK) & REG_0x80_TABLE2_BACK;
+ vref |= (fast_profile->motor_vref << REG_0x80S_TABLE4_FAST) & REG_0x80_TABLE4_FAST;
+ vref |= (fast_profile->motor_vref << REG_0x80S_TABLE5_GO_HOME) & REG_0x80_TABLE5_GO_HOME;
+ reg->set8(REG_0x80, vref);
+ }
/* substract acceleration distance from feedl */
feedl=feed_steps;
feedl <<= static_cast<unsigned>(motor_profile.step_type);
- dist = scan_table.steps_count / step_multiplier;
- if (use_fast_fed)
- {
- dist += (fast_table.steps_count / step_multiplier) * 2;
+ dist = scan_table.table.size() / step_multiplier;
+
+ if (use_fast_fed) {
+ dist += (fast_table.table.size() / step_multiplier) * 2;
}
- DBG(DBG_io2, "%s: acceleration distance=%d\n", __func__, dist);
/* get sure when don't insane value : XXX STEF XXX in this case we should
* fall back to single table move */
@@ -906,15 +800,15 @@ static void gl843_init_motor_regs_scan(Genesys_Device* dev,
}
reg->set24(REG_FEEDL, feedl);
- DBG(DBG_io, "%s: feedl=%d\n", __func__, feedl);
- /* doesn't seem to matter that much */
+ // doesn't seem to matter that much
+ std::uint32_t z1, z2;
sanei_genesys_calculate_zmod(use_fast_fed,
- exposure,
+ exposure,
scan_table.table,
- scan_table.steps_count / step_multiplier,
- feedl,
- scan_table.steps_count / step_multiplier,
+ scan_table.table.size() / step_multiplier,
+ feedl,
+ scan_table.table.size() / step_multiplier,
&z1,
&z2);
if(scan_yres>600)
@@ -924,47 +818,46 @@ static void gl843_init_motor_regs_scan(Genesys_Device* dev,
}
reg->set24(REG_Z1MOD, z1);
- DBG(DBG_info, "%s: z1 = %d\n", __func__, z1);
-
reg->set24(REG_Z2MOD, z2);
- DBG(DBG_info, "%s: z2 = %d\n", __func__, z2);
- r = sanei_genesys_get_address(reg, REG_0x1E);
- r->value &= 0xf0; /* 0 dummy lines */
- r->value |= scan_dummy; /* dummy lines */
+ reg->set8_mask(REG_0x1E, scan_dummy, 0x0f);
reg->set8_mask(REG_0x67, static_cast<unsigned>(motor_profile.step_type) << REG_0x67S_STEPSEL, 0xc0);
- reg->set8_mask(REG_0x68, static_cast<unsigned>(motor_profile.step_type) << REG_0x68S_FSTPSEL, 0xc0);
+ reg->set8_mask(REG_0x68, static_cast<unsigned>(fast_profile->step_type) << REG_0x68S_FSTPSEL, 0xc0);
// steps for STOP table
- reg->set8(REG_FMOVDEC, fast_table.steps_count / step_multiplier);
+ reg->set8(REG_FMOVDEC, fast_table.table.size() / step_multiplier);
- /* Vref XXX STEF XXX : optical divider or step type ? */
- r = sanei_genesys_get_address (reg, 0x80);
- if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE))
+ if (dev->model->model_id == ModelId::PANASONIC_KV_SS080 ||
+ dev->model->model_id == ModelId::HP_SCANJET_4850C ||
+ dev->model->model_id == ModelId::HP_SCANJET_G4010 ||
+ dev->model->model_id == ModelId::HP_SCANJET_G4050 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I)
{
- r->value = 0x50;
- coeff = sensor.get_hwdpi_divisor_for_dpi(scan_yres);
+ // FIXME: take this information from motor struct
+ std::uint8_t reg_vref = reg->get8(0x80);
+ reg_vref = 0x50;
+ unsigned coeff = sensor.full_resolution / scan_yres;
if (dev->model->motor_id == MotorId::KVSS080) {
- if(coeff>=1)
- {
- r->value |= 0x05;
+ if (coeff >= 1) {
+ reg_vref |= 0x05;
+ }
+ } else {
+ switch (coeff) {
+ case 4:
+ reg_vref |= 0x0a;
+ break;
+ case 2:
+ reg_vref |= 0x0f;
+ break;
+ case 1:
+ reg_vref |= 0x0f;
+ break;
}
}
- else {
- switch(coeff)
- {
- case 4:
- r->value |= 0x0a;
- break;
- case 2:
- r->value |= 0x0f;
- break;
- case 1:
- r->value |= 0x0f;
- break;
- }
- }
+ reg->set8(REG_0x80, reg_vref);
}
}
@@ -981,7 +874,6 @@ static void gl843_init_motor_regs_scan(Genesys_Device* dev,
* @param pixels logical number of pixels to use
* @param channels number of color channles used (1 or 3)
* @param depth bit depth of the scan (1, 8 or 16 bits)
- * @param ccd_size_divisor true specifies how much x coordinates must be shrunk
* @param color_filter to choose the color channel used in gray scans
* @param flags to drive specific settings such no calibration, XPA use ...
*/
@@ -990,57 +882,54 @@ static void gl843_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
const ScanSession& session)
{
DBG_HELPER_ARGS(dbg, "exposure=%d", exposure);
- unsigned int dpihw;
unsigned int tgtime; /**> exposure time multiplier */
- GenesysRegister *r;
/* tgtime */
tgtime = exposure / 65536 + 1;
DBG(DBG_io2, "%s: tgtime=%d\n", __func__, tgtime);
- // to manage high resolution device while keeping good low resolution scanning speed, we make
- // hardware dpi vary
- dpihw = sensor.get_register_hwdpi(session.output_resolution);
- DBG(DBG_io2, "%s: dpihw=%d\n", __func__, dpihw);
-
- /* sensor parameters */
- gl843_setup_sensor(dev, sensor, reg);
-
- // resolution is divided according to CKSEL
- unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel();
- DBG(DBG_io2, "%s: ccd_pixels_per_system_pixel=%d\n", __func__, ccd_pixels_per_system_pixel);
+ // sensor parameters
+ scanner_setup_sensor(*dev, sensor, *reg);
dev->cmd_set->set_fe(dev, sensor, AFE_SET);
/* enable shading */
regs_set_optical_off(dev->model->asic_type, *reg);
- r = sanei_genesys_get_address (reg, REG_0x01);
if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
- (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION ||
- (dev->model->flags & GENESYS_FLAG_CALIBRATION_HOST_SIDE)))
+ has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) ||
+ session.use_host_side_calib)
{
- r->value &= ~REG_0x01_DVDSET;
+ reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET;
+
} else {
- r->value |= REG_0x01_DVDSET;
+ reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET;
}
- bool use_shdarea = dpihw > 600;
+ bool use_shdarea = false;
if (dev->model->model_id == ModelId::CANON_4400F) {
use_shdarea = session.params.xres <= 600;
} else if (dev->model->model_id == ModelId::CANON_8400F) {
use_shdarea = session.params.xres <= 400;
+ } else if (dev->model->model_id == ModelId::CANON_8600F ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I)
+ {
+ use_shdarea = true;
+ } else {
+ use_shdarea = session.params.xres > 600;
}
+
if (use_shdarea) {
- r->value |= REG_0x01_SHDAREA;
+ reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA;
} else {
- r->value &= ~REG_0x01_SHDAREA;
+ reg->find_reg(REG_0x01).value &= ~REG_0x01_SHDAREA;
}
- r = sanei_genesys_get_address (reg, REG_0x03);
if (dev->model->model_id == ModelId::CANON_8600F) {
- r->value |= REG_0x03_AVEENB;
+ reg->find_reg(REG_0x03).value |= REG_0x03_AVEENB;
} else {
- r->value &= ~REG_0x03_AVEENB;
+ reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB;
}
// FIXME: we probably don't need to set exposure to registers at this point. It was this way
@@ -1049,43 +938,40 @@ static void gl843_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
!has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
/* select XPA */
- r->value &= ~REG_0x03_XPASEL;
+ reg->find_reg(REG_0x03).value &= ~REG_0x03_XPASEL;
if (has_flag(session.params.flags, ScanFlag::USE_XPA)) {
- r->value |= REG_0x03_XPASEL;
+ reg->find_reg(REG_0x03).value |= REG_0x03_XPASEL;
}
reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA);
- /* BW threshold */
- r = sanei_genesys_get_address(reg, REG_0x2E);
- r->value = dev->settings.threshold;
- r = sanei_genesys_get_address(reg, REG_0x2F);
- r->value = dev->settings.threshold;
+ // BW threshold
+ reg->set8(REG_0x2E, 0x7f);
+ reg->set8(REG_0x2F, 0x7f);
/* monochrome / color scan */
- r = sanei_genesys_get_address(reg, REG_0x04);
switch (session.params.depth) {
case 8:
- r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
+ reg->find_reg(REG_0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
break;
case 16:
- r->value &= ~REG_0x04_LINEART;
- r->value |= REG_0x04_BITSET;
+ reg->find_reg(REG_0x04).value &= ~REG_0x04_LINEART;
+ reg->find_reg(REG_0x04).value |= REG_0x04_BITSET;
break;
}
- r->value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
+ reg->find_reg(REG_0x04).value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
if (session.params.channels == 1)
{
switch (session.params.color_filter)
{
case ColorFilter::RED:
- r->value |= 0x14;
+ reg->find_reg(REG_0x04).value |= 0x14;
break;
case ColorFilter::BLUE:
- r->value |= 0x1c;
+ reg->find_reg(REG_0x04).value |= 0x1c;
break;
case ColorFilter::GREEN:
- r->value |= 0x18;
+ reg->find_reg(REG_0x04).value |= 0x18;
break;
default:
break; // should not happen
@@ -1093,10 +979,10 @@ static void gl843_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
} else {
switch (dev->frontend.layout.type) {
case FrontendType::WOLFSON:
- r->value |= 0x10; // pixel by pixel
+ reg->find_reg(REG_0x04).value |= 0x10; // pixel by pixel
break;
case FrontendType::ANALOG_DEVICES:
- r->value |= 0x20; // slow color pixel by pixel
+ reg->find_reg(REG_0x04).value |= 0x20; // slow color pixel by pixel
break;
default:
throw SaneException("Invalid frontend type %d",
@@ -1104,7 +990,10 @@ static void gl843_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
}
}
- sanei_genesys_set_dpihw(*reg, sensor, dpihw);
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution,
+ session.params.channels,
+ session.params.scan_method);
+ sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw);
if (should_enable_gamma(session, sensor)) {
reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
@@ -1112,28 +1001,18 @@ static void gl843_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB;
}
- unsigned dpiset = session.output_resolution * session.ccd_size_divisor *
- ccd_pixels_per_system_pixel;
-
- if (sensor.dpiset_override != 0) {
- dpiset = sensor.dpiset_override;
- }
- reg->set16(REG_DPISET, dpiset);
- DBG(DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset);
+ reg->set16(REG_DPISET, sensor.register_dpiset);
reg->set16(REG_STRPIXEL, session.pixel_startx);
reg->set16(REG_ENDPIXEL, session.pixel_endx);
/* MAXWD is expressed in 2 words unit */
/* nousedspace = (mem_bank_range * 1024 / 256 -1 ) * 4; */
- // BUG: the division by ccd_size_divisor likely does not make sense
- reg->set24(REG_MAXWD, (session.output_line_bytes / session.ccd_size_divisor) >> 1);
-
+ // BUG: the division by optical and full resolution factor likely does not make sense
+ reg->set24(REG_MAXWD, (session.output_line_bytes *
+ session.optical_resolution / session.full_resolution) >> 1);
reg->set16(REG_LPERIOD, exposure / tgtime);
- DBG(DBG_io2, "%s: exposure used=%d\n", __func__, exposure/tgtime);
-
- r = sanei_genesys_get_address (reg, REG_DUMMY);
- r->value = sensor.dummy_pixel;
+ reg->set8(REG_DUMMY, sensor.dummy_pixel);
}
void CommandSetGl843::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
@@ -1170,42 +1049,15 @@ void CommandSetGl843::init_regs_for_scan_session(Genesys_Device* dev, const Gene
if (exposure < 0) {
throw std::runtime_error("Exposure not defined in sensor definition");
}
- const auto& motor_profile = sanei_genesys_get_motor_profile(*gl843_motor_profiles,
- dev->model->motor_id,
- exposure);
-
- DBG(DBG_info, "%s : exposure=%d pixels\n", __func__, exposure);
- DBG(DBG_info, "%s : scan_step_type=%d\n", __func__,
- static_cast<unsigned>(motor_profile.step_type));
+ const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure, session);
// now _LOGICAL_ optical values used are known, setup registers
gl843_init_optical_regs_scan(dev, sensor, reg, exposure, session);
+ gl843_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure, slope_dpi,
+ session.optical_line_count, dummy, session.params.starty,
+ session.params.flags);
- /*** motor parameters ***/
- MotorFlag mflags = MotorFlag::NONE;
- if (has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) {
- mflags |= MotorFlag::DISABLE_BUFFER_FULL_MOVE;
- }
- if (has_flag(session.params.flags, ScanFlag::FEEDING)) {
- mflags |= MotorFlag::FEED;
- }
- if (has_flag(session.params.flags, ScanFlag::USE_XPA)) {
- mflags |= MotorFlag::USE_XPA;
- }
- if (has_flag(session.params.flags, ScanFlag::REVERSE)) {
- mflags |= MotorFlag::REVERSE;
- }
-
- unsigned scan_lines = dev->model->is_cis ? session.output_line_count * session.params.channels
- : session.output_line_count;
-
- gl843_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure, slope_dpi,
- scan_lines, dummy, session.params.starty, mflags);
-
- dev->read_buffer.clear();
- dev->read_buffer.alloc(session.buffer_size_read);
-
- build_image_pipeline(dev, session);
+ setup_image_pipeline(*dev, session);
dev->read_active = true;
@@ -1224,33 +1076,46 @@ ScanSession CommandSetGl843::calculate_scan_session(const Genesys_Device* dev,
DBG_HELPER(dbg);
debug_dump(DBG_info, settings);
- int start;
-
- /* we have 2 domains for ccd: xres below or above half ccd max dpi */
- unsigned ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(settings.xres);
+ ScanFlag flags = ScanFlag::NONE;
+ float move = 0.0f;
if (settings.scan_method == ScanMethod::TRANSPARENCY ||
settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
- start = static_cast<int>(dev->model->x_offset_ta);
+ // note: scanner_move_to_ta() function has already been called and the sensor is at the
+ // transparency adapter
+ if (!dev->ignore_offsets) {
+ move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta;
+ }
+ flags |= ScanFlag::USE_XPA;
} else {
- start = static_cast<int>(dev->model->x_offset);
+ if (!dev->ignore_offsets) {
+ move = dev->model->y_offset;
+ }
}
- if (dev->model->model_id == ModelId::CANON_8600F)
+ move += settings.tl_y;
+
+ int move_dpi = dev->motor.base_ydpi;
+ move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
+
+ float start = 0.0f;
+ if (settings.scan_method==ScanMethod::TRANSPARENCY ||
+ settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
- // FIXME: this is probably just an artifact of a bug elsewhere
- start /= ccd_size_divisor;
+ start = dev->model->x_offset_ta;
+ } else {
+ start = dev->model->x_offset;
}
+ start = start + settings.tl_x;
- start += static_cast<int>(settings.tl_x);
- start = static_cast<int>((start * sensor.optical_res) / MM_PER_INCH);
+ start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
ScanSession session;
session.params.xres = settings.xres;
session.params.yres = settings.yres;
- session.params.startx = start; // not used
- session.params.starty = 0; // not used
+ session.params.startx = static_cast<unsigned>(start);
+ session.params.starty = static_cast<unsigned>(move);
session.params.pixels = settings.pixels;
session.params.requested_pixels = settings.requested_pixels;
session.params.lines = settings.lines;
@@ -1259,8 +1124,7 @@ ScanSession CommandSetGl843::calculate_scan_session(const Genesys_Device* dev,
session.params.scan_method = settings.scan_method;
session.params.scan_mode = settings.scan_mode;
session.params.color_filter = settings.color_filter;
- session.params.flags = ScanFlag::NONE;
-
+ session.params.flags = flags;
compute_session(dev, session, sensor);
return session;
@@ -1352,8 +1216,6 @@ void CommandSetGl843::detect_document_end(Genesys_Device* dev) const
auto skip_lines = scan_end_lines - output_lines;
if (remaining_lines > skip_lines) {
- DBG(DBG_io, "%s: skip_lines=%zu\n", __func__, skip_lines);
-
remaining_lines -= skip_lines;
dev->get_pipeline_source().set_remaining_bytes(remaining_lines *
dev->session.output_line_bytes_raw);
@@ -1363,194 +1225,6 @@ void CommandSetGl843::detect_document_end(Genesys_Device* dev) const
}
}
-// enables or disables XPA slider motor
-void gl843_set_xpa_motor_power(Genesys_Device* dev, Genesys_Register_Set& regs, bool set)
-{
- DBG_HELPER(dbg);
- uint8_t val;
-
- if (dev->model->model_id == ModelId::CANON_8400F) {
-
- if (set) {
- val = dev->interface->read_register(0x6c);
- val &= ~(REG_0x6C_GPIO16 | REG_0x6C_GPIO13);
- if (dev->session.output_resolution >= 2400) {
- val &= ~REG_0x6C_GPIO10;
- }
- dev->interface->write_register(0x6c, val);
-
- val = dev->interface->read_register(0xa9);
- val |= REG_0xA9_GPO30;
- val &= ~REG_0xA9_GPO29;
- dev->interface->write_register(0xa9, val);
- } else {
- val = dev->interface->read_register(0x6c);
- val |= REG_0x6C_GPIO16 | REG_0x6C_GPIO13;
- dev->interface->write_register(0x6c, val);
-
- val = dev->interface->read_register(0xa9);
- val &= ~REG_0xA9_GPO30;
- val |= REG_0xA9_GPO29;
- dev->interface->write_register(0xa9, val);
- }
- } else if (dev->model->model_id == ModelId::CANON_8600F) {
- if (set) {
- val = dev->interface->read_register(REG_0x6C);
- val &= ~REG_0x6C_GPIO14;
- if (dev->session.output_resolution >= 2400) {
- val |= REG_0x6C_GPIO10;
- }
- dev->interface->write_register(REG_0x6C, val);
-
- val = dev->interface->read_register(REG_0xA6);
- val |= REG_0xA6_GPIO17;
- val &= ~REG_0xA6_GPIO23;
- dev->interface->write_register(REG_0xA6, val);
- } else {
- val = dev->interface->read_register(REG_0x6C);
- val |= REG_0x6C_GPIO14;
- val &= ~REG_0x6C_GPIO10;
- dev->interface->write_register(REG_0x6C, val);
-
- val = dev->interface->read_register(REG_0xA6);
- val &= ~REG_0xA6_GPIO17;
- val &= ~REG_0xA6_GPIO23;
- dev->interface->write_register(REG_0xA6, val);
- }
- } else if (dev->model->model_id == ModelId::HP_SCANJET_G4050) {
- if (set) {
- // set MULTFILM et GPOADF
- val = dev->interface->read_register(REG_0x6B);
- val |=REG_0x6B_MULTFILM|REG_0x6B_GPOADF;
- dev->interface->write_register(REG_0x6B, val);
-
- val = dev->interface->read_register(REG_0x6C);
- val &= ~REG_0x6C_GPIO15;
- dev->interface->write_register(REG_0x6C, val);
-
- /* Motor power ? No move at all without this one */
- val = dev->interface->read_register(REG_0xA6);
- val |= REG_0xA6_GPIO20;
- dev->interface->write_register(REG_0xA6, val);
-
- val = dev->interface->read_register(REG_0xA8);
- val &= ~REG_0xA8_GPO27;
- dev->interface->write_register(REG_0xA8, val);
-
- val = dev->interface->read_register(REG_0xA9);
- val |= REG_0xA9_GPO32|REG_0xA9_GPO31;
- dev->interface->write_register(REG_0xA9, val);
- } else {
- // unset GPOADF
- val = dev->interface->read_register(REG_0x6B);
- val &= ~REG_0x6B_GPOADF;
- dev->interface->write_register(REG_0x6B, val);
-
- val = dev->interface->read_register(REG_0xA8);
- val |= REG_0xA8_GPO27;
- dev->interface->write_register(REG_0xA8, val);
-
- val = dev->interface->read_register(REG_0xA9);
- val &= ~REG_0xA9_GPO31;
- dev->interface->write_register(REG_0xA9, val);
- }
- }
- regs.state.is_xpa_motor_on = set;
-}
-
-
-/** @brief light XPA lamp
- * toggle gpios to switch off regular lamp and light on the
- * XPA light
- * @param dev device to set up
- */
-static void gl843_set_xpa_lamp_power(Genesys_Device* dev, bool set)
-{
- 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_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_7200I, ScanMethod::TRANSPARENCY, {
- }, {
- { 0xa6, 0x40, 0x70 }, // BUG: remove this cleanup write, it was enabled by accident
- }
- },
- { ModelId::PLUSTEK_OPTICFILM_7200I, ScanMethod::TRANSPARENCY_INFRARED, {
- { 0xa8, 0x07, 0x07 },
- }, {
- { 0xa8, 0x00, 0x07 },
- }
- },
- { ModelId::PLUSTEK_OPTICFILM_7300, ScanMethod::TRANSPARENCY, {}, {} },
- { ModelId::PLUSTEK_OPTICFILM_7500I, ScanMethod::TRANSPARENCY, {}, {} },
- { ModelId::PLUSTEK_OPTICFILM_7500I, ScanMethod::TRANSPARENCY_INFRARED, {
- { 0xa8, 0x07, 0x07 },
- }, {
- { 0xa8, 0x00, 0x07 },
- }
- },
- };
-
- 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;
- }
- }
-
- // BUG: we're currently calling the function in shut down path of regular lamp
- if (set) {
- throw SaneException("Unexpected code path entered");
- }
-
- GenesysRegisterSettingSet regs = {
- { 0xa6, 0x40, 0x70 },
- };
- apply_reg_settings_to_device(*dev, regs);
- // TODO: throw exception when we're only calling this function in error return path
- // throw SaneException("Could not find XPA lamp settings");
-}
-
// Send the low-level scan command
void CommandSetGl843::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg, bool start_motor) const
@@ -1580,30 +1254,44 @@ void CommandSetGl843::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens
}
if (reg->state.is_xpa_on && reg->state.is_lamp_on) {
- gl843_set_xpa_lamp_power(dev, true);
+ dev->cmd_set->set_xpa_lamp_power(*dev, true);
}
if (reg->state.is_xpa_on) {
- gl843_set_xpa_motor_power(dev, *reg, true);
+ dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY);
}
// blinking led
dev->interface->write_register(REG_0x7E, 0x01);
break;
case GpioId::CANON_8400F:
+ if (dev->session.params.xres == 3200)
+ {
+ GenesysRegisterSettingSet reg_settings = {
+ { 0x6c, 0x00, 0x02 },
+ };
+ apply_reg_settings_to_device(*dev, reg_settings);
+ }
+ if (reg->state.is_xpa_on && reg->state.is_lamp_on) {
+ dev->cmd_set->set_xpa_lamp_power(*dev, true);
+ }
+ if (reg->state.is_xpa_on) {
+ dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY);
+ }
+ break;
case GpioId::CANON_8600F:
if (reg->state.is_xpa_on && reg->state.is_lamp_on) {
- gl843_set_xpa_lamp_power(dev, true);
+ dev->cmd_set->set_xpa_lamp_power(*dev, true);
}
if (reg->state.is_xpa_on) {
- gl843_set_xpa_motor_power(dev, *reg, true);
+ dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY);
}
break;
case GpioId::PLUSTEK_OPTICFILM_7200I:
case GpioId::PLUSTEK_OPTICFILM_7300:
case GpioId::PLUSTEK_OPTICFILM_7500I: {
if (reg->state.is_xpa_on && reg->state.is_lamp_on) {
- gl843_set_xpa_lamp_power(dev, true);
+ dev->cmd_set->set_xpa_lamp_power(*dev, true);
}
break;
}
@@ -1612,8 +1300,7 @@ void CommandSetGl843::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens
break;
}
- // clear scan and feed count
- dev->interface->write_register(REG_0x0D, REG_0x0D_CLRLNCNT | REG_0x0D_CLRMCNT);
+ scanner_clear_scan_and_feed_counts(*dev);
// enable scan and motor
uint8_t val = dev->interface->read_register(REG_0x01);
@@ -1622,11 +1309,26 @@ void CommandSetGl843::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens
scanner_start_action(*dev, start_motor);
- if (reg->state.is_motor_on) {
- dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
- }
- if (reg->state.is_xpa_motor_on) {
- dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
+ switch (reg->state.motor_mode) {
+ case MotorMode::PRIMARY: {
+ if (reg->state.is_motor_on) {
+ dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
+ }
+ break;
+ }
+ case MotorMode::PRIMARY_AND_SECONDARY: {
+ if (reg->state.is_motor_on) {
+ dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
+ dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
+ }
+ break;
+ }
+ case MotorMode::SECONDARY: {
+ if (reg->state.is_motor_on) {
+ dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
+ }
+ break;
+ }
}
}
@@ -1640,10 +1342,8 @@ void CommandSetGl843::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg,
// post scan gpio
dev->interface->write_register(0x7e, 0x00);
- // turn off XPA lamp if needed
- // BUG: the if condition below probably shouldn't be enabled when XPA is off
- if (reg->state.is_xpa_on || reg->state.is_lamp_on) {
- gl843_set_xpa_lamp_power(dev, false);
+ if (reg->state.is_xpa_on) {
+ dev->cmd_set->set_xpa_lamp_power(*dev, false);
}
if (!dev->model->is_sheetfed) {
@@ -1658,202 +1358,79 @@ void CommandSetGl843::move_back_home(Genesys_Device* dev, bool wait_until_home)
scanner_move_back_home(*dev, wait_until_home);
}
-// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi
-// from very top of scanner
-void CommandSetGl843::search_start_position(Genesys_Device* dev) const
-{
- DBG_HELPER(dbg);
- Genesys_Register_Set local_reg;
-
- int pixels = 600;
- int dpi = 300;
-
- local_reg = dev->reg;
-
- /* sets for a 200 lines * 600 pixels */
- /* normal scan with no shading */
-
- // FIXME: the current approach of doing search only for one resolution does not work on scanners
- // whith employ different sensors with potentially different settings.
- const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method);
-
- ScanSession session;
- session.params.xres = dpi;
- session.params.yres = dpi;
- session.params.startx = 0;
- session.params.starty = 0; // we should give a small offset here - ~60 steps
- session.params.pixels = 600;
- session.params.lines = dev->model->search_lines;
- session.params.depth = 8;
- session.params.channels = 1;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::GRAY;
- session.params.color_filter = ColorFilter::GREEN;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::IGNORE_LINE_DISTANCE |
- ScanFlag::DISABLE_BUFFER_FULL_MOVE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &local_reg, session);
-
- // send to scanner
- dev->interface->write_registers(local_reg);
-
- dev->cmd_set->begin_scan(dev, sensor, &local_reg, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("search_start_position");
- end_scan(dev, &local_reg, true);
- dev->reg = local_reg;
- return;
- }
-
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- Image image = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes_raw);
-
- scanner_stop_action_no_move(*dev, local_reg);
-
- if (DBG_LEVEL >= DBG_data) {
- sanei_genesys_write_pnm_file("gl843_search_position.pnm", image);
- }
-
- dev->cmd_set->end_scan(dev, &local_reg, true);
-
- /* update regs to copy ASIC internal state */
- dev->reg = local_reg;
-
- for (auto& sensor_update :
- sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method))
- {
- sanei_genesys_search_reference_point(dev, sensor_update, image.get_row_ptr(0), 0, dpi,
- pixels, dev->model->search_lines);
- }
-}
-
-// sets up register for coarse gain calibration
-// todo: check it for scanners using it
-void CommandSetGl843::init_regs_for_coarse_calibration(Genesys_Device* dev,
- const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs) const
-{
- DBG_HELPER(dbg);
-
- ScanFlag flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
-
- if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
- dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) {
- flags |= ScanFlag::USE_XPA;
- }
-
- ScanSession session;
- session.params.xres = dev->settings.xres;
- session.params.yres = dev->settings.yres;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel();
- session.params.lines = 20;
- session.params.depth = 16;
- session.params.channels = dev->settings.get_channels();
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = dev->settings.scan_mode;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = flags;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &regs, session);
-
- sanei_genesys_set_motor_power(regs, false);
-
- DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__,
- sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres);
-
- dev->interface->write_registers(regs);
-}
-
// init registers for shading calibration shading calibration is done at dpihw
void CommandSetGl843::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
- int move, resolution, dpihw, factor;
-
- /* initial calibration reg values */
- regs = dev->reg;
-
- dev->calib_channels = 3;
+ int move;
+ float calib_size_mm = 0;
if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
- dev->calib_lines = dev->model->shading_ta_lines;
+ calib_size_mm = dev->model->y_size_calib_ta_mm;
} else {
- dev->calib_lines = dev->model->shading_lines;
+ calib_size_mm = dev->model->y_size_calib_mm;
}
- dpihw = sensor.get_logical_hwdpi(dev->settings.xres);
- factor=sensor.optical_res/dpihw;
- resolution=dpihw;
+ unsigned resolution = sensor.shading_resolution;
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, dev->calib_channels,
+ unsigned channels = 3;
+ const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
- if ((dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
- dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) &&
- dev->model->model_id == ModelId::CANON_8600F &&
- dev->settings.xres == 4800)
- {
- float offset = static_cast<float>(dev->model->x_offset_ta);
- offset /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution);
- offset = static_cast<float>((offset * calib_sensor.optical_res) / MM_PER_INCH);
+ unsigned calib_pixels = 0;
+ unsigned calib_pixels_offset = 0;
- float size = static_cast<float>(dev->model->x_size_ta);
- size /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution);
- size = static_cast<float>((size * calib_sensor.optical_res) / MM_PER_INCH);
+ if (should_calibrate_only_active_area(*dev, dev->settings)) {
+ float offset = dev->model->x_offset_ta;
+ // FIXME: we should use resolution here
+ offset = static_cast<float>((offset * dev->settings.xres) / MM_PER_INCH);
- dev->calib_pixels_offset = static_cast<std::size_t>(offset);
- dev->calib_pixels = static_cast<std::size_t>(size);
- }
- else
- {
- dev->calib_pixels_offset = 0;
- dev->calib_pixels = calib_sensor.sensor_pixels / factor;
- }
+ float size = dev->model->x_size_ta;
+ size = static_cast<float>((size * dev->settings.xres) / MM_PER_INCH);
- dev->calib_resolution = resolution;
+ calib_pixels_offset = static_cast<std::size_t>(offset);
+ calib_pixels = static_cast<std::size_t>(size);
+ } else {
+ calib_pixels_offset = 0;
+ calib_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
+ }
ScanFlag flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
- ScanFlag::DISABLE_BUFFER_FULL_MOVE |
- ScanFlag::IGNORE_LINE_DISTANCE;
+ ScanFlag::DISABLE_BUFFER_FULL_MOVE;
if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
- // note: move_to_ta() function has already been called and the sensor is at the
+ // note: scanner_move_to_ta() function has already been called and the sensor is at the
// transparency adapter
move = static_cast<int>(dev->model->y_offset_calib_white_ta - dev->model->y_offset_sensor_to_ta);
+ if (dev->model->model_id == ModelId::CANON_8600F && resolution == 2400) {
+ move /= 2;
+ }
+ if (dev->model->model_id == ModelId::CANON_8600F && resolution == 4800) {
+ move /= 4;
+ }
flags |= ScanFlag::USE_XPA;
} else {
move = static_cast<int>(dev->model->y_offset_calib_white);
}
move = static_cast<int>((move * resolution) / MM_PER_INCH);
+ unsigned calib_lines = static_cast<unsigned>(calib_size_mm * resolution / MM_PER_INCH);
ScanSession session;
session.params.xres = resolution;
session.params.yres = resolution;
- session.params.startx = dev->calib_pixels_offset;
+ session.params.startx = calib_pixels_offset;
session.params.starty = move;
- session.params.pixels = dev->calib_pixels;
- session.params.lines = dev->calib_lines;
+ session.params.pixels = calib_pixels;
+ session.params.lines = calib_lines;
session.params.depth = 16;
- session.params.channels = dev->calib_channels;
+ session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = dev->settings.scan_mode;
session.params.color_filter = dev->settings.color_filter;
@@ -1862,89 +1439,7 @@ void CommandSetGl843::init_regs_for_shading(Genesys_Device* dev, const Genesys_S
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
- // the pixel number may be updated to conform to scanner constraints
- dev->calib_pixels = session.output_pixels;
-
dev->calib_session = session;
- dev->calib_total_bytes_to_read = session.output_total_bytes_raw;
-
- dev->interface->write_registers(regs);
-}
-
-/** @brief set up registers for the actual scan
- */
-void CommandSetGl843::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const
-{
- DBG_HELPER(dbg);
- float move;
- int move_dpi;
- float start;
-
- debug_dump(DBG_info, dev->settings);
-
- move_dpi = dev->motor.base_ydpi;
-
- ScanFlag flags = ScanFlag::NONE;
-
- if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
- dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
- {
- // note: move_to_ta() function has already been called and the sensor is at the
- // transparency adapter
- if (dev->ignore_offsets) {
- move = 0;
- } else {
- move = static_cast<float>(dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta);
- }
- flags |= ScanFlag::USE_XPA;
- } else {
- if (dev->ignore_offsets) {
- move = 0;
- } else {
- move = static_cast<float>(dev->model->y_offset);
- }
- }
-
- move += static_cast<float>(dev->settings.tl_y);
- move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
-
- /* start */
- if (dev->settings.scan_method==ScanMethod::TRANSPARENCY ||
- dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
- {
- start = static_cast<float>(dev->model->x_offset_ta);
- } else {
- start = static_cast<float>(dev->model->x_offset);
- }
-
- if (dev->model->model_id == ModelId::CANON_8400F ||
- dev->model->model_id == ModelId::CANON_8600F)
- {
- // FIXME: this is probably just an artifact of a bug elsewhere
- start /= sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres);
- }
-
- start = static_cast<float>(start + dev->settings.tl_x);
- start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
-
- ScanSession session;
- session.params.xres = dev->settings.xres;
- session.params.yres = dev->settings.yres;
- session.params.startx = static_cast<unsigned>(start);
- session.params.starty = static_cast<unsigned>(move);
- session.params.pixels = dev->settings.pixels;
- session.params.requested_pixels = dev->settings.requested_pixels;
- session.params.lines = dev->settings.lines;
- session.params.depth = dev->settings.depth;
- session.params.channels = dev->settings.get_channels();
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = dev->settings.scan_mode;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = flags;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &dev->reg, session);
}
/**
@@ -1975,8 +1470,7 @@ void CommandSetGl843::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor
gamma[i * 2 + size * 4 + 1] = (bgamma[i] >> 8) & 0xff;
}
- dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3,
- ScannerInterface::FLAG_SWAP_REGISTERS);
+ dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3);
}
/* this function does the led calibration by scanning one line of the calibration
@@ -1987,607 +1481,69 @@ void CommandSetGl843::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor
SensorExposure CommandSetGl843::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
- DBG_HELPER(dbg);
- int num_pixels;
- int avg[3], avga, avge;
- int turn;
- uint16_t expr, expg, expb;
-
- // offset calibration is always done in color mode
- unsigned channels = 3;
-
- // take a copy, as we're going to modify exposure
- auto calib_sensor = sanei_genesys_find_sensor(dev, sensor.optical_res, channels,
- dev->settings.scan_method);
-
- num_pixels = (calib_sensor.sensor_pixels * calib_sensor.optical_res) / calib_sensor.optical_res;
-
- /* initial calibration reg values */
- regs = dev->reg;
-
- ScanSession session;
- session.params.xres = calib_sensor.sensor_pixels;
- session.params.yres = dev->motor.base_ydpi;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = num_pixels;
- session.params.lines = 1;
- session.params.depth = 16;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, calib_sensor);
-
- init_regs_for_scan_session(dev, calib_sensor, &regs, session);
-
- dev->interface->write_registers(regs);
-
-/*
- we try to get equal bright leds here:
-
- loop:
- average per color
- adjust exposure times
- */
-
- expr = calib_sensor.exposure.red;
- expg = calib_sensor.exposure.green;
- expb = calib_sensor.exposure.blue;
-
- turn = 0;
-
- bool acceptable = false;
- do
- {
-
- calib_sensor.exposure.red = expr;
- calib_sensor.exposure.green = expg;
- calib_sensor.exposure.blue = expb;
-
- regs_set_exposure(dev->model->asic_type, regs, calib_sensor.exposure);
-
- dev->interface->write_registers(regs);
-
- DBG(DBG_info, "%s: starting first line reading\n", __func__);
- dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("led_calibration");
- move_back_home(dev, true);
- return calib_sensor.exposure;
- }
-
- auto image = read_unshuffled_image_from_scanner(dev, session,
- session.output_total_bytes_raw);
- scanner_stop_action_no_move(*dev, regs);
-
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[30];
- std::snprintf(fn, 30, "gl843_led_%02d.pnm", turn);
- sanei_genesys_write_pnm_file(fn, image);
- }
-
- acceptable = true;
-
- for (unsigned ch = 0; ch < channels; ch++) {
- avg[ch] = 0;
- for (std::size_t x = 0; x < image.get_width(); x++) {
- avg[ch] += image.get_raw_channel(x, 0, ch);
- }
- avg[ch] /= image.get_width();
- }
-
- DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]);
-
- acceptable = true;
-
- if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 ||
- avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 ||
- avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95)
- acceptable = false;
-
- if (!acceptable)
- {
- avga = (avg[0] + avg[1] + avg[2]) / 3;
- expr = (expr * avga) / avg[0];
- expg = (expg * avga) / avg[1];
- expb = (expb * avga) / avg[2];
-/*
- keep the resulting exposures below this value.
- too long exposure drives the ccd into saturation.
- we may fix this by relying on the fact that
- we get a striped scan without shading, by means of
- statistical calculation
-*/
- avge = (expr + expg + expb) / 3;
-
- /* don't overflow max exposure */
- if (avge > 3000)
- {
- expr = (expr * 2000) / avge;
- expg = (expg * 2000) / avge;
- expb = (expb * 2000) / avge;
- }
- if (avge < 50)
- {
- expr = (expr * 50) / avge;
- expg = (expg * 50) / avge;
- expb = (expb * 50) / avge;
- }
-
- }
- scanner_stop_action(*dev);
-
- turn++;
-
- }
- while (!acceptable && turn < 100);
-
- DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, expr, expg, expb);
-
- move_back_home(dev, true);
-
- return calib_sensor.exposure;
-}
-
-
-
-/**
- * average dark pixels of a 8 bits scan of a given channel
- */
-static int dark_average_channel(const Image& image, unsigned black, unsigned channel)
-{
- auto channels = get_pixel_channels(image.get_format());
-
- unsigned avg[3];
-
- // computes average values on black margin
- for (unsigned ch = 0; ch < channels; ch++) {
- avg[ch] = 0;
- unsigned count = 0;
- // FIXME: start with the second line because the black pixels often have noise on the first
- // line; the cause is probably incorrectly cleaned up previous scan
- for (std::size_t y = 1; y < image.get_height(); y++) {
- for (unsigned j = 0; j < black; j++) {
- avg[ch] += image.get_raw_channel(j, y, ch);
- count++;
- }
- }
- if (count > 0) {
- avg[ch] /= count;
- }
- DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, ch, avg[ch]);
- }
- DBG(DBG_info, "%s: average = %d\n", __func__, avg[channel]);
- return avg[channel];
+ return scanner_led_calibration(*dev, sensor, regs);
}
-/** @brief calibrate AFE offset
- * Iterate doing scans at target dpi until AFE offset if correct. One
- * color line is scanned at a time. Scanning head doesn't move.
- * @param dev device to calibrate
- */
void CommandSetGl843::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
- DBG_HELPER(dbg);
-
- if (dev->frontend.layout.type != FrontendType::WOLFSON)
- return;
-
- unsigned channels;
- int pass, resolution, lines;
- int topavg[3], bottomavg[3], avg[3];
- int top[3], bottom[3], black_pixels, pixels, factor, dpihw;
-
- /* offset calibration is always done in color mode */
- channels = 3;
- lines = 8;
-
- // compute divider factor to compute final pixels number
- dpihw = sensor.get_logical_hwdpi(dev->settings.xres);
- factor = sensor.optical_res / dpihw;
- resolution = dpihw;
-
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
- dev->settings.scan_method);
-
- int target_pixels = calib_sensor.sensor_pixels / factor;
- int start_pixel = 0;
- black_pixels = calib_sensor.black_pixels / factor;
-
- if ((dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
- dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) &&
- dev->model->model_id == ModelId::CANON_8600F &&
- dev->settings.xres == 4800)
- {
- start_pixel = static_cast<int>(dev->model->x_offset_ta);
- start_pixel /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution);
- start_pixel = static_cast<int>((start_pixel * calib_sensor.optical_res) / MM_PER_INCH);
-
- target_pixels = static_cast<int>(dev->model->x_size_ta);
- target_pixels /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution);
- target_pixels = static_cast<int>((target_pixels * calib_sensor.optical_res) / MM_PER_INCH);
- }
-
- ScanFlag flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
-
- if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
- dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
- {
- flags |= ScanFlag::USE_XPA;
- }
-
- ScanSession session;
- session.params.xres = resolution;
- session.params.yres = resolution;
- session.params.startx = start_pixel;
- session.params.starty = 0;
- session.params.pixels = target_pixels;
- session.params.lines = lines;
- session.params.depth = 8;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = ColorFilter::RED;
- session.params.flags = flags;
- compute_session(dev, session, calib_sensor);
- pixels = session.output_pixels;
-
- DBG(DBG_io, "%s: dpihw =%d\n", __func__, dpihw);
- DBG(DBG_io, "%s: factor =%d\n", __func__, factor);
- DBG(DBG_io, "%s: resolution =%d\n", __func__, resolution);
- DBG(DBG_io, "%s: pixels =%d\n", __func__, pixels);
- DBG(DBG_io, "%s: black_pixels=%d\n", __func__, black_pixels);
- init_regs_for_scan_session(dev, calib_sensor, &regs, session);
-
- sanei_genesys_set_motor_power(regs, false);
-
- // init gain and offset
- for (unsigned ch = 0; ch < 3; ch++)
- {
- bottom[ch] = 10;
- dev->frontend.set_offset(ch, bottom[ch]);
- dev->frontend.set_gain(ch, 0);
- }
- dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
-
- // scan with bottom AFE settings
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting first line reading\n", __func__);
-
- dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("offset_calibration");
- scanner_stop_action_no_move(*dev, regs);
- return;
- }
-
- auto first_line = read_unshuffled_image_from_scanner(dev, session,
- session.output_total_bytes_raw);
- scanner_stop_action_no_move(*dev, regs);
-
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[40];
- std::snprintf(fn, 40, "gl843_bottom_offset_%03d_%03d_%03d.pnm",
- bottom[0], bottom[1], bottom[2]);
- sanei_genesys_write_pnm_file(fn, first_line);
- }
-
- for (unsigned ch = 0; ch < 3; ch++) {
- bottomavg[ch] = dark_average_channel(first_line, black_pixels, ch);
- DBG(DBG_io2, "%s: bottom avg %d=%d\n", __func__, ch, bottomavg[ch]);
- }
-
- // now top value
- for (unsigned ch = 0; ch < 3; ch++) {
- top[ch] = 255;
- dev->frontend.set_offset(ch, top[ch]);
- }
- dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
-
- // scan with top AFE values
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting second line reading\n", __func__);
-
- dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
- auto second_line = read_unshuffled_image_from_scanner(dev, session,
- session.output_total_bytes_raw);
- scanner_stop_action_no_move(*dev, regs);
-
- for (unsigned ch = 0; ch < 3; ch++){
- topavg[ch] = dark_average_channel(second_line, black_pixels, ch);
- DBG(DBG_io2, "%s: top avg %d=%d\n", __func__, ch, topavg[ch]);
- }
-
- pass = 0;
-
- std::vector<uint8_t> debug_image;
- size_t debug_image_lines = 0;
- std::string debug_image_info;
-
- /* loop until acceptable level */
- while ((pass < 32)
- && ((top[0] - bottom[0] > 1)
- || (top[1] - bottom[1] > 1) || (top[2] - bottom[2] > 1)))
- {
- pass++;
-
- // settings for new scan
- for (unsigned ch = 0; ch < 3; ch++) {
- if (top[ch] - bottom[ch] > 1) {
- dev->frontend.set_offset(ch, (top[ch] + bottom[ch]) / 2);
- }
- }
- dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
-
- // scan with no move
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting second line reading\n", __func__);
- dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
- second_line = read_unshuffled_image_from_scanner(dev, session,
- session.output_total_bytes_raw);
- scanner_stop_action_no_move(*dev, regs);
-
- if (DBG_LEVEL >= DBG_data)
- {
- char title[100];
- std::snprintf(title, 100, "lines: %d pixels_per_line: %d offsets[0..2]: %d %d %d\n",
- lines, pixels,
- dev->frontend.get_offset(0),
- dev->frontend.get_offset(1),
- dev->frontend.get_offset(2));
- debug_image_info += title;
- std::copy(second_line.get_row_ptr(0),
- second_line.get_row_ptr(0) + second_line.get_row_bytes() * second_line.get_height(),
- std::back_inserter(debug_image));
- debug_image_lines += lines;
- }
-
- for (unsigned ch = 0; ch < 3; ch++) {
- avg[ch] = dark_average_channel(second_line, black_pixels, ch);
- DBG(DBG_info, "%s: avg[%d]=%d offset=%d\n", __func__, ch, avg[ch],
- dev->frontend.get_offset(ch));
- }
-
- // compute new boundaries
- for (unsigned ch = 0; ch < 3; ch++) {
- if (topavg[ch] >= avg[ch]) {
- topavg[ch] = avg[ch];
- top[ch] = dev->frontend.get_offset(ch);
- } else {
- bottomavg[ch] = avg[ch];
- bottom[ch] = dev->frontend.get_offset(ch);
- }
- }
- }
-
- if (DBG_LEVEL >= DBG_data)
- {
- sanei_genesys_write_file("gl843_offset_all_desc.txt",
- reinterpret_cast<const std::uint8_t*>(debug_image_info.data()),
- debug_image_info.size());
- sanei_genesys_write_pnm_file("gl843_offset_all.pnm",
- debug_image.data(), session.params.depth, channels, pixels,
- debug_image_lines);
- }
-
- DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
- dev->frontend.get_offset(0),
- dev->frontend.get_offset(1),
- dev->frontend.get_offset(2));
+ scanner_offset_calibration(*dev, sensor, regs);
}
-
-/* alternative coarse gain calibration
- this on uses the settings from offset_calibration and
- uses only one scanline
- */
-/*
- with offset and coarse calibration we only want to get our input range into
- a reasonable shape. the fine calibration of the upper and lower bounds will
- be done with shading.
- */
void CommandSetGl843::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const
{
- DBG_HELPER_ARGS(dbg, "dpi = %d", dpi);
- int factor, dpihw;
- float coeff;
- int lines;
- int resolution;
-
- if (dev->frontend.layout.type != FrontendType::WOLFSON)
- return;
+ scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
+}
- dpihw = sensor.get_logical_hwdpi(dpi);
- factor=sensor.optical_res/dpihw;
+// wait for lamp warmup by scanning the same line until difference
+// between 2 scans is below a threshold
+void CommandSetGl843::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
+ Genesys_Register_Set* reg) const
+{
+ DBG_HELPER(dbg);
+ (void) sensor;
- // coarse gain calibration is always done in color mode
unsigned channels = 3;
+ unsigned resolution = dev->model->get_resolution_settings(dev->settings.scan_method)
+ .get_nearest_resolution_x(600);
- /* follow CKSEL */
- if (dev->model->sensor_id == SensorId::CCD_KVSS080) {
- if(dev->settings.xres<sensor.optical_res)
- {
- coeff = 0.9f;
- }
- else
- {
- coeff=1.0;
- }
- }
- else
- {
- coeff=1.0;
- }
- resolution=dpihw;
- lines=10;
- int target_pixels = sensor.sensor_pixels / factor;
+ const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
+ dev->settings.scan_method);
+ unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH / 2;
- ScanFlag flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
+ *reg = dev->reg;
+ auto flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA |
+ ScanFlag::SINGLE_LINE |
+ ScanFlag::IGNORE_STAGGER_OFFSET |
+ ScanFlag::IGNORE_COLOR_OFFSET;
if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
flags |= ScanFlag::USE_XPA;
}
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
- dev->settings.scan_method);
-
ScanSession session;
session.params.xres = resolution;
session.params.yres = resolution;
- session.params.startx = 0;
+ session.params.startx = (num_pixels / 2) * resolution / calib_sensor.full_resolution;
session.params.starty = 0;
- session.params.pixels = target_pixels;
- session.params.lines = lines;
- session.params.depth = 8;
+ session.params.pixels = num_pixels;
+ session.params.lines = 1;
+ session.params.depth = dev->model->bpp_color_values.front();
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = flags;
- compute_session(dev, session, calib_sensor);
- std::size_t pixels = session.output_pixels;
-
- try {
- init_regs_for_scan_session(dev, calib_sensor, &regs, session);
- } catch (...) {
- catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); });
- throw;
- }
-
- sanei_genesys_set_motor_power(regs, false);
-
- dev->interface->write_registers(regs);
-
- dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
- dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("coarse_gain_calibration");
- scanner_stop_action(*dev);
- move_back_home(dev, true);
- return;
- }
-
- auto line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes_raw);
- scanner_stop_action_no_move(*dev, regs);
-
- if (DBG_LEVEL >= DBG_data) {
- sanei_genesys_write_pnm_file("gl843_gain.pnm", line);
- }
-
- // average value on each channel
- for (unsigned ch = 0; ch < channels; ch++) {
-
- std::vector<uint16_t> values;
- // FIXME: start from the second line because the first line often has artifacts. Probably
- // caused by unclean cleanup of previous scan
- for (std::size_t x = pixels / 4; x < (pixels * 3 / 4); x++) {
- values.push_back(line.get_raw_channel(x, 1, ch));
- }
- // pick target value at 95th percentile of all values. There may be a lot of black values
- // in transparency scans for example
- std::sort(values.begin(), values.end());
- uint16_t curr_output = values[unsigned((values.size() - 1) * 0.95)];
- float target_value = calib_sensor.gain_white_ref * coeff;
-
- int code = compute_frontend_gain(curr_output, target_value, dev->frontend.layout.type);
- dev->frontend.set_gain(ch, code);
-
- DBG(DBG_proc, "%s: channel %d, max=%d, target=%d, setting:%d\n", __func__, ch, curr_output,
- static_cast<int>(target_value), code);
- }
-
- if (dev->model->is_cis) {
- uint8_t gain0 = dev->frontend.get_gain(0);
- if (gain0 > dev->frontend.get_gain(1)) {
- gain0 = dev->frontend.get_gain(1);
- }
- if (gain0 > dev->frontend.get_gain(2)) {
- gain0 = dev->frontend.get_gain(2);
- }
- dev->frontend.set_gain(0, gain0);
- dev->frontend.set_gain(1, gain0);
- dev->frontend.set_gain(2, gain0);
- }
-
- if (channels == 1) {
- dev->frontend.set_gain(0, dev->frontend.get_gain(1));
- dev->frontend.set_gain(2, dev->frontend.get_gain(1));
- }
-
- scanner_stop_action(*dev);
-
- move_back_home(dev, true);
-}
-
-// wait for lamp warmup by scanning the same line until difference
-// between 2 scans is below a threshold
-void CommandSetGl843::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* reg, int* channels,
- int* total_size) const
-{
- DBG_HELPER(dbg);
- int num_pixels;
- int dpihw;
- int resolution;
- int factor;
-
- /* setup scan */
- *channels=3;
- resolution=600;
- dpihw = sensor.get_logical_hwdpi(resolution);
- resolution=dpihw;
-
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, *channels,
- dev->settings.scan_method);
- factor = calib_sensor.optical_res/dpihw;
- num_pixels = calib_sensor.sensor_pixels/(factor*2);
- *total_size = num_pixels * 3 * 1;
-
- *reg = dev->reg;
-
- ScanSession session;
- session.params.xres = resolution;
- session.params.yres = resolution;
- session.params.startx = num_pixels/2;
- session.params.starty = 0;
- session.params.pixels = num_pixels;
- session.params.lines = 1;
- session.params.depth = 8;
- session.params.channels = *channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, reg, session);
sanei_genesys_set_motor_power(*reg, false);
- dev->interface->write_registers(*reg);
}
/**
@@ -2654,7 +1610,7 @@ void CommandSetGl843::asic_boot(Genesys_Device* dev, bool cold) const
val = dev->reg.find_reg(0x0b).value & REG_0x0B_DRAMSEL;
val = (val | REG_0x0B_ENBDRAM);
dev->interface->write_register(REG_0x0B, val);
- dev->reg.find_reg(0x0b).value = val;
+ dev->reg.find_reg(0x0b).value = val;
if (dev->model->model_id == ModelId::CANON_8400F) {
dev->interface->write_0x8c(0x1e, 0x01);
@@ -2691,18 +1647,11 @@ void CommandSetGl843::asic_boot(Genesys_Device* dev, bool cold) const
val = (dev->reg.find_reg(0x0b).value & ~REG_0x0B_CLKSET) | clock_freq;
dev->interface->write_register(REG_0x0B, val);
- dev->reg.find_reg(0x0b).value = val;
+ dev->reg.find_reg(0x0b).value = val;
/* prevent further writings by bulk write register */
dev->reg.remove_reg(0x0b);
- if (dev->model->model_id != ModelId::CANON_8600F) {
- // set up end access
- // FIXME: this is overwritten in gl843_init_gpio
- dev->interface->write_register(REG_0xA7, 0x04);
- dev->interface->write_register(REG_0xA9, 0x00);
- }
-
// set RAM read address
dev->interface->write_register(REG_0x29, 0x00);
dev->interface->write_register(REG_0x2A, 0x00);
@@ -2710,8 +1659,6 @@ void CommandSetGl843::asic_boot(Genesys_Device* dev, bool cold) const
// setup gpio
gl843_init_gpio(dev);
-
- scanner_move(*dev, dev->model->default_method, 300, Direction::FORWARD);
dev->interface->sleep_ms(100);
}
@@ -2724,7 +1671,7 @@ void CommandSetGl843::init(Genesys_Device* dev) const
DBG_INIT ();
DBG_HELPER(dbg);
- sanei_genesys_asic_init(dev, 0);
+ sanei_genesys_asic_init(dev);
}
void CommandSetGl843::update_hardware_sensors(Genesys_Scanner* s) const
@@ -2754,216 +1701,10 @@ void CommandSetGl843::update_hardware_sensors(Genesys_Scanner* s) const
}
}
-/** @brief move sensor to transparency adaptor
- * Move sensor to the calibration of the transparency adapator (XPA).
- * @param dev device to use
- */
-void CommandSetGl843::move_to_ta(Genesys_Device* dev) const
+void CommandSetGl843::update_home_sensor_gpio(Genesys_Device& dev) const
{
DBG_HELPER(dbg);
-
- const auto& resolution_settings = dev->model->get_resolution_settings(dev->model->default_method);
- float resolution = resolution_settings.get_min_resolution_y();
-
- unsigned multiplier = 16;
- if (dev->model->model_id == ModelId::CANON_8400F) {
- multiplier = 4;
- }
- unsigned feed = static_cast<unsigned>(multiplier * (dev->model->y_offset_sensor_to_ta * resolution) /
- MM_PER_INCH);
- scanner_move(*dev, dev->model->default_method, feed, Direction::FORWARD);
-}
-
-
-/** @brief 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 CommandSetGl843::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor,
- bool forward, bool black) const
-{
- DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse");
- unsigned int pixels, lines, channels;
- Genesys_Register_Set local_reg;
- int dpi;
- unsigned int pass, count, found, x, y;
-
- dev->cmd_set->set_fe(dev, sensor, AFE_SET);
- scanner_stop_action(*dev);
-
- /* set up for a gray scan at lowest dpi */
- dpi = sanei_genesys_get_lowest_dpi(dev);
- channels = 1;
-
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, dpi, channels,
- dev->settings.scan_method);
-
- /* 10 MM */
- /* lines = (10 * dpi) / MM_PER_INCH; */
- /* shading calibation is done with dev->motor.base_ydpi */
- lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi;
- pixels = (calib_sensor.sensor_pixels * dpi) / calib_sensor.optical_res;
-
- dev->set_head_pos_zero(ScanHeadId::PRIMARY);
-
- local_reg = dev->reg;
-
- ScanSession session;
- session.params.xres = dpi;
- session.params.yres = dpi;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = pixels;
- session.params.lines = lines;
- session.params.depth = 8;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::GRAY;
- session.params.color_filter = ColorFilter::RED;
- session.params.flags = ScanFlag::DISABLE_SHADING | ScanFlag::DISABLE_SHADING;
- if (!forward) {
- session.params.flags = ScanFlag::REVERSE;
- }
- compute_session(dev, session, calib_sensor);
-
- init_regs_for_scan_session(dev, calib_sensor, &local_reg, session);
-
- dev->interface->write_registers(local_reg);
-
- dev->cmd_set->begin_scan(dev, calib_sensor, &local_reg, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("search_strip");
- scanner_stop_action(*dev);
- return;
- }
-
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- auto data = read_unshuffled_image_from_scanner(dev, session,
- session.output_total_bytes_raw);
-
- scanner_stop_action(*dev);
-
- pass = 0;
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[40];
- std::snprintf(fn, 40, "gl843_search_strip_%s_%s%02d.pnm",
- black ? "black" : "white", forward ? "fwd" : "bwd", pass);
- sanei_genesys_write_pnm_file(fn, data);
- }
-
- /* loop until strip is found or maximum pass number done */
- found = 0;
- while (pass < 20 && !found)
- {
- dev->interface->write_registers(local_reg);
-
- // now start scan
- dev->cmd_set->begin_scan(dev, calib_sensor, &local_reg, true);
-
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- data = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes_raw);
-
- scanner_stop_action(*dev);
-
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[40];
- std::snprintf(fn, 40, "gl843_search_strip_%s_%s%02d.pnm",
- black ? "black" : "white", forward ? "fwd" : "bwd", pass);
- sanei_genesys_write_pnm_file(fn, data);
- }
-
- /* search data to find black strip */
- /* when searching forward, we only need one line of the searched color since we
- * will scan forward. But when doing backward search, we need all the area of the
- * same color */
- if (forward)
- {
- for (y = 0; y < lines && !found; y++)
- {
- count = 0;
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < pixels; x++)
- {
- /* when searching for black, detect white pixels */
- if (black && data.get_raw_channel(x, y, 0) > 90) {
- count++;
- }
- /* when searching for white, detect black pixels */
- if (!black && data.get_raw_channel(x, y, 0) < 60) {
- count++;
- }
- }
-
- /* at end of line, if count >= 3%, line is not fully of the desired color
- * so we must go to next line of the buffer */
- /* count*100/pixels < 3 */
- if ((count * 100) / pixels < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__,
- pass, y);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
- (100 * count) / pixels);
- }
- }
- }
- else /* since calibration scans are done forward, we need the whole area
- to be of the required color when searching backward */
- {
- count = 0;
- for (y = 0; y < lines; y++)
- {
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < pixels; x++)
- {
- // when searching for black, detect white pixels
- if (black && data.get_raw_channel(x, y, 0) > 90) {
- count++;
- }
- // when searching for white, detect black pixels
- if (!black && data.get_raw_channel(x, y, 0) < 60) {
- count++;
- }
- }
- }
-
- /* at end of area, if count >= 3%, area is not fully of the desired color
- * so we must go to next buffer */
- if ((count * 100) / (pixels * lines) < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
- (100 * count) / pixels);
- }
- }
- pass++;
- }
- if (found)
- {
- DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white");
- }
- else
- {
- throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white");
- }
+ (void) dev;
}
/**
@@ -2974,43 +1715,27 @@ void CommandSetGl843::send_shading_data(Genesys_Device* dev, const Genesys_Senso
uint8_t* data, int size) const
{
DBG_HELPER(dbg);
- uint32_t final_size, length, i;
+ uint32_t final_size, i;
uint8_t *buffer;
- int count,offset;
- GenesysRegister *r;
- uint16_t strpixel, endpixel, startx;
-
- offset=0;
- length=size;
- r = sanei_genesys_get_address(&dev->reg, REG_0x01);
- if (r->value & REG_0x01_SHDAREA)
- {
- /* recompute STRPIXEL used shading calibration so we can
- * compute offset within data for SHDAREA case */
-
- // FIXME: the following is likely incorrect
- // start coordinate in optical dpi coordinates
- startx = (sensor.dummy_pixel / sensor.ccd_pixels_per_system_pixel()) / dev->session.hwdpi_divisor;
- startx *= dev->session.pixel_count_multiplier;
-
- /* current scan coordinates */
- strpixel = dev->session.pixel_startx;
- endpixel = dev->session.pixel_endx;
-
- if (dev->model->model_id == ModelId::CANON_4400F ||
- dev->model->model_id == ModelId::CANON_8600F)
- {
- int half_ccd_factor = dev->session.optical_resolution /
- sensor.get_logical_hwdpi(dev->session.output_resolution);
- strpixel /= half_ccd_factor * sensor.ccd_pixels_per_system_pixel();
- endpixel /= half_ccd_factor * sensor.ccd_pixels_per_system_pixel();
- }
+ int count;
+
+ int offset = 0;
+ unsigned length = size;
+
+ if (dev->reg.get8(REG_0x01) & REG_0x01_SHDAREA) {
+ offset = dev->session.params.startx * sensor.shading_resolution /
+ dev->session.params.xres;
- /* 16 bit words, 2 words per color, 3 color channels */
- offset=(strpixel-startx)*2*2*3;
- length=(endpixel-strpixel)*2*2*3;
- DBG(DBG_info, "%s: STRPIXEL=%d, ENDPIXEL=%d, startx=%d\n", __func__, strpixel, endpixel,
- startx);
+ length = dev->session.output_pixels * sensor.shading_resolution /
+ dev->session.params.xres;
+
+ offset += sensor.shading_pixel_offset;
+
+ // 16 bit words, 2 words per color, 3 color channels
+ length *= 2 * 2 * 3;
+ offset *= 2 * 2 * 3;
+ } else {
+ offset += sensor.shading_pixel_offset * 2 * 2 * 3;
}
dev->interface->record_key_value("shading_offset", std::to_string(offset));
@@ -3024,6 +1749,14 @@ void CommandSetGl843::send_shading_data(Genesys_Device* dev, const Genesys_Senso
/* copy regular shading data to the expected layout */
buffer = final_data.data();
count = 0;
+ if (offset < 0) {
+ count += (-offset);
+ length -= (-offset);
+ offset = 0;
+ }
+ if (static_cast<int>(length) + offset > static_cast<int>(size)) {
+ length = size - offset;
+ }
/* loop over calibration data */
for (i = 0; i < length; i++)
@@ -3036,8 +1769,7 @@ void CommandSetGl843::send_shading_data(Genesys_Device* dev, const Genesys_Senso
}
}
- dev->interface->write_buffer(0x3c, 0, final_data.data(), count,
- ScannerInterface::FLAG_SMALL_ADDRESS);
+ dev->interface->write_buffer(0x3c, 0, final_data.data(), count);
}
bool CommandSetGl843::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
@@ -3051,10 +1783,5 @@ void CommandSetGl843::wait_for_motor_stop(Genesys_Device* dev) const
(void) dev;
}
-std::unique_ptr<CommandSet> create_gl843_cmd_set()
-{
- return std::unique_ptr<CommandSet>(new CommandSetGl843{});
-}
-
} // namespace gl843
} // namespace genesys
diff --git a/backend/genesys/gl843.h b/backend/genesys/gl843.h
index 9f0a9e9..5326a2d 100644
--- a/backend/genesys/gl843.h
+++ b/backend/genesys/gl843.h
@@ -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,17 +60,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs, int* channels,
- int* total_size) const override;
-
- 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_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@@ -86,8 +80,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,17 +95,14 @@ public:
void update_hardware_sensors(struct Genesys_Scanner* s) const override;
+ 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,
int size) const override;
diff --git a/backend/genesys/gl843_registers.h b/backend/genesys/gl843_registers.h
index 8ecb0fc..cbc38c0 100644
--- a/backend/genesys/gl843_registers.h
+++ b/backend/genesys/gl843_registers.h
@@ -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;
diff --git a/backend/genesys/gl846.cpp b/backend/genesys/gl846.cpp
index d309d29..cae7414 100644
--- a/backend/genesys/gl846.cpp
+++ b/backend/genesys/gl846.cpp
@@ -61,38 +61,12 @@ namespace gl846 {
/**
* compute the step multiplier used
*/
-static int
-gl846_get_step_multiplier (Genesys_Register_Set * regs)
+static int gl846_get_step_multiplier (Genesys_Register_Set * regs)
{
- GenesysRegister *r = sanei_genesys_get_address(regs, 0x9d);
- int value = 1;
- if (r != nullptr) {
- value = (r->value & 0x0f)>>1;
- value = 1 << value;
- }
- DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value);
- return value;
-}
-
-/** @brief sensor specific settings
-*/
-static void gl846_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs)
-{
- DBG_HELPER(dbg);
-
- for (const auto& reg : sensor.custom_regs) {
- regs->set8(reg.address, reg.value);
- }
-
- regs->set16(REG_EXPR, sensor.exposure.red);
- regs->set16(REG_EXPG, sensor.exposure.green);
- regs->set16(REG_EXPB, sensor.exposure.blue);
-
- dev->segment_order = sensor.segment_order;
+ unsigned value = (regs->get8(0x9d) & 0x0f) >> 1;
+ return 1 << value;
}
-
/** @brief set all registers to default values .
* This function is called only once at the beginning and
* fills register startup values for registers reused across scans.
@@ -108,23 +82,56 @@ gl846_init_registers (Genesys_Device * dev)
dev->reg.clear();
dev->reg.init_reg(0x01, 0x60);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ dev->reg.init_reg(0x01, 0x22);
+ }
dev->reg.init_reg(0x02, 0x38);
dev->reg.init_reg(0x03, 0x03);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ dev->reg.init_reg(0x03, 0xbf);
+ }
dev->reg.init_reg(0x04, 0x22);
dev->reg.init_reg(0x05, 0x60);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ dev->reg.init_reg(0x05, 0x48);
+ }
dev->reg.init_reg(0x06, 0x10);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ dev->reg.init_reg(0x06, 0xf0);
+ }
dev->reg.init_reg(0x08, 0x60);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ dev->reg.init_reg(0x08, 0x00);
+ }
dev->reg.init_reg(0x09, 0x00);
dev->reg.init_reg(0x0a, 0x00);
dev->reg.init_reg(0x0b, 0x8b);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
+ dev->reg.init_reg(0x0b, 0x2a);
+ }
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ dev->reg.init_reg(0x0b, 0x4a);
+ }
dev->reg.init_reg(0x0c, 0x00);
dev->reg.init_reg(0x0d, 0x00);
- dev->reg.init_reg(0x10, 0x00);
- dev->reg.init_reg(0x11, 0x00);
- dev->reg.init_reg(0x12, 0x00);
- dev->reg.init_reg(0x13, 0x00);
- dev->reg.init_reg(0x14, 0x00);
- dev->reg.init_reg(0x15, 0x00);
+ dev->reg.init_reg(0x10, 0x00); // exposure, set during sensor setup
+ dev->reg.init_reg(0x11, 0x00); // exposure, set during sensor setup
+ dev->reg.init_reg(0x12, 0x00); // exposure, set during sensor setup
+ dev->reg.init_reg(0x13, 0x00); // exposure, set during sensor setup
+ dev->reg.init_reg(0x14, 0x00); // exposure, set during sensor setup
+ dev->reg.init_reg(0x15, 0x00); // exposure, set during sensor setup
dev->reg.init_reg(0x16, 0xbb); // SENSOR_DEF
dev->reg.init_reg(0x17, 0x13); // SENSOR_DEF
dev->reg.init_reg(0x18, 0x10); // SENSOR_DEF
@@ -133,33 +140,52 @@ gl846_init_registers (Genesys_Device * dev)
dev->reg.init_reg(0x1b, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x1c, 0x20); // SENSOR_DEF
dev->reg.init_reg(0x1d, 0x06); // SENSOR_DEF
- dev->reg.init_reg(0x1e, 0xf0);
+ dev->reg.init_reg(0x1e, 0xf0); // WDTIME, LINESEL: set during sensor and motor setup
+
+ // SCANFED
dev->reg.init_reg(0x1f, 0x01);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400) {
+ dev->reg.init_reg(0x1f, 0x00);
+ }
+
dev->reg.init_reg(0x20, 0x03);
- dev->reg.init_reg(0x21, 0x10);
- dev->reg.init_reg(0x22, 0x60);
- dev->reg.init_reg(0x23, 0x60);
- dev->reg.init_reg(0x24, 0x60);
- dev->reg.init_reg(0x25, 0x00);
- dev->reg.init_reg(0x26, 0x00);
- dev->reg.init_reg(0x27, 0x00);
- dev->reg.init_reg(0x2c, 0x00);
- dev->reg.init_reg(0x2d, 0x00);
- dev->reg.init_reg(0x2e, 0x80);
- dev->reg.init_reg(0x2f, 0x80);
- dev->reg.init_reg(0x30, 0x00);
- dev->reg.init_reg(0x31, 0x00);
- dev->reg.init_reg(0x32, 0x00);
- dev->reg.init_reg(0x33, 0x00);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ dev->reg.init_reg(0x20, 0x55);
+ }
+ dev->reg.init_reg(0x21, 0x10); // STEPNO: set during motor setup
+ dev->reg.init_reg(0x22, 0x60); // FWDSTEP: set during motor setup
+ dev->reg.init_reg(0x23, 0x60); // BWDSTEP: set during motor setup
+ dev->reg.init_reg(0x24, 0x60); // FASTNO: set during motor setup
+ dev->reg.init_reg(0x25, 0x00); // LINCNT: set during motor setup
+ dev->reg.init_reg(0x26, 0x00); // LINCNT: set during motor setup
+ dev->reg.init_reg(0x27, 0x00); // LINCNT: set during motor setup
+ dev->reg.init_reg(0x2c, 0x00); // DPISET: set during sensor setup
+ dev->reg.init_reg(0x2d, 0x00); // DPISET: set during sensor setup
+ dev->reg.init_reg(0x2e, 0x80); // BWHI: set during sensor setup
+ dev->reg.init_reg(0x2f, 0x80); // BWLOW: set during sensor setup
+ dev->reg.init_reg(0x30, 0x00); // STRPIXEL: set during sensor setup
+ dev->reg.init_reg(0x31, 0x00); // STRPIXEL: set during sensor setup
+ dev->reg.init_reg(0x32, 0x00); // ENDPIXEL: set during sensor setup
+ dev->reg.init_reg(0x33, 0x00); // ENDPIXEL: set during sensor setup
+
+ // DUMMY: the number of CCD dummy pixels
dev->reg.init_reg(0x34, 0x1f);
- dev->reg.init_reg(0x35, 0x00);
- dev->reg.init_reg(0x36, 0x40);
- dev->reg.init_reg(0x37, 0x00);
- dev->reg.init_reg(0x38, 0x2a);
- dev->reg.init_reg(0x39, 0xf8);
- dev->reg.init_reg(0x3d, 0x00);
- dev->reg.init_reg(0x3e, 0x00);
- dev->reg.init_reg(0x3f, 0x01);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ dev->reg.init_reg(0x34, 0x14);
+ }
+
+ dev->reg.init_reg(0x35, 0x00); // MAXWD: set during scan setup
+ dev->reg.init_reg(0x36, 0x40); // MAXWD: set during scan setup
+ dev->reg.init_reg(0x37, 0x00); // MAXWD: set during scan setup
+ dev->reg.init_reg(0x38, 0x2a); // LPERIOD: set during sensor setup
+ dev->reg.init_reg(0x39, 0xf8); // LPERIOD: set during sensor setup
+ dev->reg.init_reg(0x3d, 0x00); // FEEDL: set during motor setup
+ dev->reg.init_reg(0x3e, 0x00); // FEEDL: set during motor setup
+ dev->reg.init_reg(0x3f, 0x01); // FEEDL: set during motor setup
dev->reg.init_reg(0x52, 0x02); // SENSOR_DEF
dev->reg.init_reg(0x53, 0x04); // SENSOR_DEF
dev->reg.init_reg(0x54, 0x06); // SENSOR_DEF
@@ -169,22 +195,30 @@ gl846_init_registers (Genesys_Device * dev)
dev->reg.init_reg(0x58, 0x59); // SENSOR_DEF
dev->reg.init_reg(0x59, 0x31); // SENSOR_DEF
dev->reg.init_reg(0x5a, 0x40); // SENSOR_DEF
+
+ // DECSEL, STEPTIM
dev->reg.init_reg(0x5e, 0x1f);
- dev->reg.init_reg(0x5f, 0x01);
- dev->reg.init_reg(0x60, 0x00);
- dev->reg.init_reg(0x61, 0x00);
- dev->reg.init_reg(0x62, 0x00);
- dev->reg.init_reg(0x63, 0x00);
- dev->reg.init_reg(0x64, 0x00);
- dev->reg.init_reg(0x65, 0x00);
- dev->reg.init_reg(0x67, 0x7f);
- dev->reg.init_reg(0x68, 0x7f);
- dev->reg.init_reg(0x69, 0x01);
- dev->reg.init_reg(0x6a, 0x01);
- dev->reg.init_reg(0x70, 0x01);
- dev->reg.init_reg(0x71, 0x00);
- dev->reg.init_reg(0x72, 0x02);
- dev->reg.init_reg(0x73, 0x01);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ dev->reg.init_reg(0x5e, 0x01);
+ }
+ dev->reg.init_reg(0x5f, 0x01); // FMOVDEC: overwritten during motor setup
+ dev->reg.init_reg(0x60, 0x00); // STEPSEL, Z1MOD: overwritten during motor setup
+ dev->reg.init_reg(0x61, 0x00); // Z1MOD: overwritten during motor setup
+ dev->reg.init_reg(0x62, 0x00); // Z1MOD: overwritten during motor setup
+ dev->reg.init_reg(0x63, 0x00); // FSTPSEL, Z2MOD: overwritten during motor setup
+ dev->reg.init_reg(0x64, 0x00); // Z2MOD: overwritten during motor setup
+ dev->reg.init_reg(0x65, 0x00); // Z2MOD: overwritten during motor setup
+ dev->reg.init_reg(0x67, 0x7f); // MTRPWM: overwritten during motor setup
+ dev->reg.init_reg(0x68, 0x7f); // FASTPWM: overwritten during motor setup
+ dev->reg.init_reg(0x69, 0x01); // FSHDEC: overwritten during motor setup
+ dev->reg.init_reg(0x6a, 0x01); // FMOVNO: overwritten during motor setup
+ // 0x6b, 0x6c, 0x6d, 0x6e, 0x6f - gpio
+ dev->reg.init_reg(0x70, 0x01); // SENSOR_DEF
+ dev->reg.init_reg(0x71, 0x00); // SENSOR_DEF
+ dev->reg.init_reg(0x72, 0x02); // SENSOR_DEF
+ dev->reg.init_reg(0x73, 0x01); // SENSOR_DEF
dev->reg.init_reg(0x74, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x75, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x76, 0x00); // SENSOR_DEF
@@ -194,78 +228,80 @@ gl846_init_registers (Genesys_Device * dev)
dev->reg.init_reg(0x7a, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x7b, 0x09); // SENSOR_DEF
dev->reg.init_reg(0x7c, 0x99); // SENSOR_DEF
- dev->reg.init_reg(0x7d, 0x20);
+ dev->reg.init_reg(0x7d, 0x20); // SENSOR_DEF
dev->reg.init_reg(0x7f, 0x05);
- dev->reg.init_reg(0x80, 0x4f);
- dev->reg.init_reg(0x87, 0x02);
- dev->reg.init_reg(0x94, 0xff);
- dev->reg.init_reg(0x9d, 0x04);
- dev->reg.init_reg(0x9e, 0x00);
- dev->reg.init_reg(0xa1, 0xe0);
- dev->reg.init_reg(0xa2, 0x1f);
- dev->reg.init_reg(0xab, 0xc0);
- dev->reg.init_reg(0xbb, 0x00);
- dev->reg.init_reg(0xbc, 0x0f);
- dev->reg.init_reg(0xdb, 0xff);
- dev->reg.init_reg(0xfe, 0x08);
- dev->reg.init_reg(0xff, 0x02);
- dev->reg.init_reg(0x98, 0x20);
- dev->reg.init_reg(0x99, 0x00);
- dev->reg.init_reg(0x9a, 0x90);
- dev->reg.init_reg(0x9b, 0x00);
- dev->reg.init_reg(0xf8, 0x05);
-
- const auto& sensor = sanei_genesys_find_sensor_any(dev);
- sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res);
-
- /* initalize calibration reg */
- dev->calib_reg = dev->reg;
-}
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ dev->reg.init_reg(0x7f, 0x00);
+ }
+ dev->reg.init_reg(0x80, 0x4f); // overwritten during motor setup
+ dev->reg.init_reg(0x87, 0x02); // SENSOR_DEF
-/**@brief send slope table for motor movement
- * Send slope_table in machine byte order
- * @param dev device to send slope table
- * @param table_nr index of the slope table in ASIC memory
- * Must be in the [0-4] range.
- * @param slope_table pointer to 16 bit values array of the slope table
- * @param steps number of elements in the slope table
- */
-static void gl846_send_slope_table(Genesys_Device* dev, int table_nr,
- const std::vector<uint16_t>& slope_table,
- int steps)
-{
- DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps);
- int i;
- char msg[10000];
+ // MTRPLS: pulse width of ADF motor trigger signal
+ dev->reg.init_reg(0x94, 0x00);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
+ dev->reg.init_reg(0x94, 0xff);
+ }
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
+ dev->reg.init_reg(0x98, 0x20); // ONDUR
+ dev->reg.init_reg(0x99, 0x00); // ONDUR
+ dev->reg.init_reg(0x9a, 0x90); // OFFDUR
+ dev->reg.init_reg(0x9b, 0x00); // OFFDUR
+ }
- /* sanity check */
- if(table_nr<0 || table_nr>4)
- {
- throw SaneException("invalid table number %d", table_nr);
+ dev->reg.init_reg(0x9d, 0x00); // contains STEPTIM
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
+ dev->reg.init_reg(0x9d, 0x04);
+ }
+ dev->reg.init_reg(0x9e, 0x00);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
+ dev->reg.init_reg(0xa1, 0xe0);
}
- std::vector<uint8_t> table(steps * 2);
- for (i = 0; i < steps; i++)
+ // RFHSET (SDRAM refresh time)
+ dev->reg.init_reg(0xa2, 0x1f);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
{
- table[i * 2] = slope_table[i] & 0xff;
- table[i * 2 + 1] = slope_table[i] >> 8;
+ dev->reg.init_reg(0xa2, 0x0f);
}
- if (DBG_LEVEL >= DBG_io)
+ // 0xa6, 0xa7 0xa8, 0xa9 - gpio
+
+ // Various important settings: GPOM9, MULSTOP, NODECEL, TB3TB1, TB5TB2, FIX16CLK
+ dev->reg.init_reg(0xab, 0xc0);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
{
- std::sprintf(msg, "write slope %d (%d)=", table_nr, steps);
- for (i = 0; i < steps; i++)
- {
- std::sprintf(msg+strlen(msg), "%d", slope_table[i]);
- }
- DBG (DBG_io, "%s: %s\n", __func__, msg);
+ dev->reg.init_reg(0xab, 0x01);
+ }
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
+ dev->reg.init_reg(0xbb, 0x00); // FIXME: default is the same
+ }
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
+ dev->reg.init_reg(0xbc, 0x0f);
+ dev->reg.init_reg(0xdb, 0xff);
+ }
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400) {
+ dev->reg.init_reg(0xbe, 0x07);
}
- if (dev->interface->is_mock()) {
- dev->interface->record_slope_table(table_nr, slope_table);
+ // 0xd0, 0xd1, 0xd2 - SH0DWN, SH1DWN, SH2DWN - shading bank[0..2] for CCD.
+ // Set during memory layout setup
+
+ // [0xe0..0xf7] - image buffer addresses. Set during memory layout setup
+ dev->reg.init_reg(0xf8, 0x05); // MAXSEL, MINSEL
+
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
+ dev->reg.init_reg(0xfe, 0x08); // MOTTGST, AUTO_O
+ dev->reg.init_reg(0xff, 0x02); // AUTO_S
}
- // slope table addresses are fixed
- dev->interface->write_ahb(0x10000000 + 0x4000 * table_nr, steps * 2, table.data());
+
+ const auto& sensor = sanei_genesys_find_sensor_any(dev);
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, sensor.full_resolution,
+ 3, dev->model->default_method);
+ sanei_genesys_set_dpihw(dev->reg, dpihw_sensor.register_dpihw);
}
/**
@@ -283,11 +319,8 @@ static void gl846_set_adi_fe(Genesys_Device* dev, uint8_t set)
status = scanner_read_status(*dev);
};
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s(): setting DAC %u\n", __func__,
- static_cast<unsigned>(dev->model->adc_id));
- dev->frontend = dev->frontend_initial;
+ if (set == AFE_INIT) {
+ dev->frontend = dev->frontend_initial;
}
// write them to analog frontend
@@ -326,115 +359,110 @@ void CommandSetGl846::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor,
// @brief set up motor related register for scan
static void gl846_init_motor_regs_scan(Genesys_Device* dev,
const Genesys_Sensor& sensor,
+ const ScanSession& session,
Genesys_Register_Set* reg,
- const Motor_Profile& motor_profile,
+ const MotorProfile& motor_profile,
unsigned int scan_exposure_time,
unsigned scan_yres,
unsigned int scan_lines,
unsigned int scan_dummy,
unsigned int feed_steps,
- MotorFlag flags)
+ ScanFlag flags)
{
DBG_HELPER_ARGS(dbg, "scan_exposure_time=%d, scan_yres=%d, step_type=%d, scan_lines=%d, "
"scan_dummy=%d, feed_steps=%d, flags=%x",
scan_exposure_time, scan_yres, static_cast<unsigned>(motor_profile.step_type),
scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
- int use_fast_fed;
- unsigned int fast_dpi;
- unsigned int feedl, dist;
- GenesysRegister *r;
- uint32_t z1, z2;
- unsigned int min_restep = 0x20;
- uint8_t val;
- unsigned int ccdlmt,tgtime;
unsigned step_multiplier = gl846_get_step_multiplier(reg);
- use_fast_fed=0;
- /* no fast fed since feed works well */
- if (dev->settings.yres == 4444 && feed_steps > 100 && !has_flag(flags, MotorFlag::FEED)) {
- use_fast_fed = 1;
+ bool use_fast_fed = false;
+ if (dev->settings.yres == 4444 && feed_steps > 100 && !has_flag(flags, ScanFlag::FEEDING)) {
+ use_fast_fed = true;
+ }
+ if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
+ use_fast_fed = false;
}
- DBG (DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed);
reg->set24(REG_LINCNT, scan_lines);
- DBG (DBG_io, "%s: lincnt=%d\n", __func__, scan_lines);
- /* compute register 02 value */
- r = sanei_genesys_get_address(reg, REG_0x02);
- r->value = 0x00;
- sanei_genesys_set_motor_power(*reg, true);
+ reg->set8(REG_0x02, 0);
+ sanei_genesys_set_motor_power(*reg, true);
- if (use_fast_fed)
- r->value |= REG_0x02_FASTFED;
- else
- r->value &= ~REG_0x02_FASTFED;
+ std::uint8_t reg02 = reg->get8(REG_0x02);
+ if (use_fast_fed) {
+ reg02 |= REG_0x02_FASTFED;
+ } else {
+ reg02 &= ~REG_0x02_FASTFED;
+ }
- if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) {
- r->value |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
+ if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
+ reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
}
- if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE) ||(scan_yres>=sensor.optical_res)) {
- r->value |= REG_0x02_ACDCDIS;
+ if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) || (scan_yres>=sensor.full_resolution)) {
+ reg02 |= REG_0x02_ACDCDIS;
}
- if (has_flag(flags, MotorFlag::REVERSE)) {
- r->value |= REG_0x02_MTRREV;
+ if (has_flag(flags, ScanFlag::REVERSE)) {
+ reg02 |= REG_0x02_MTRREV;
} else {
- r->value &= ~REG_0x02_MTRREV;
+ reg02 &= ~REG_0x02_MTRREV;
}
+ reg->set8(REG_0x02, reg02);
- /* scan and backtracking slope table */
- auto scan_table = sanei_genesys_slope_table(dev->model->asic_type, scan_yres,
- scan_exposure_time, dev->motor.base_ydpi,
- step_multiplier, motor_profile);
+ // scan and backtracking slope table
+ auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres,
+ scan_exposure_time, step_multiplier, motor_profile);
- gl846_send_slope_table(dev, SCAN_TABLE, scan_table.table, scan_table.steps_count);
- gl846_send_slope_table(dev, BACKTRACK_TABLE, scan_table.table, scan_table.steps_count);
+ scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table);
+ scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table);
+ scanner_send_slope_table(dev, sensor, STOP_TABLE, scan_table.table);
- /* fast table */
- fast_dpi=sanei_genesys_get_lowest_ydpi(dev);
+ reg->set8(REG_STEPNO, scan_table.table.size() / step_multiplier);
+ reg->set8(REG_FASTNO, scan_table.table.size() / step_multiplier);
+ reg->set8(REG_FSHDEC, scan_table.table.size() / step_multiplier);
- // BUG: looks like for fast moves we use inconsistent step type
- StepType fast_step_type = motor_profile.step_type;
- if (static_cast<unsigned>(motor_profile.step_type) >= static_cast<unsigned>(StepType::QUARTER)) {
- fast_step_type = StepType::QUARTER;
+ // fast table
+ const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
+ if (fast_profile == nullptr) {
+ fast_profile = &motor_profile;
}
- Motor_Profile fast_motor_profile = motor_profile;
- fast_motor_profile.step_type = fast_step_type;
+ auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
+ *fast_profile);
- auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_dpi,
- scan_exposure_time, dev->motor.base_ydpi,
- step_multiplier, fast_motor_profile);
+ scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table);
+ scanner_send_slope_table(dev, sensor, HOME_TABLE, fast_table.table);
- gl846_send_slope_table(dev, STOP_TABLE, fast_table.table, fast_table.steps_count);
- gl846_send_slope_table(dev, FAST_TABLE, fast_table.table, fast_table.steps_count);
- gl846_send_slope_table(dev, HOME_TABLE, fast_table.table, fast_table.steps_count);
+ reg->set8(REG_FMOVNO, fast_table.table.size() / step_multiplier);
+ reg->set8(REG_FMOVDEC, fast_table.table.size() / step_multiplier);
- /* correct move distance by acceleration and deceleration amounts */
- feedl=feed_steps;
- if (use_fast_fed)
- {
- feedl <<= static_cast<unsigned>(fast_step_type);
- dist = (scan_table.steps_count + 2 * fast_table.steps_count);
- /* TODO read and decode REG_0xAB */
- r = sanei_genesys_get_address (reg, 0x5e);
- dist += (r->value & 31);
- /* FEDCNT */
- r = sanei_genesys_get_address(reg, REG_FEDCNT);
- dist += r->value;
+ if (motor_profile.motor_vref != -1 && fast_profile->motor_vref != 1) {
+ std::uint8_t vref = 0;
+ vref |= (motor_profile.motor_vref << REG_0x80S_TABLE1_NORMAL) & REG_0x80_TABLE1_NORMAL;
+ vref |= (motor_profile.motor_vref << REG_0x80S_TABLE2_BACK) & REG_0x80_TABLE2_BACK;
+ vref |= (fast_profile->motor_vref << REG_0x80S_TABLE4_FAST) & REG_0x80_TABLE4_FAST;
+ vref |= (fast_profile->motor_vref << REG_0x80S_TABLE5_GO_HOME) & REG_0x80_TABLE5_GO_HOME;
+ reg->set8(REG_0x80, vref);
}
- else
- {
+
+ unsigned feedl = feed_steps;
+ unsigned dist = 0;
+ if (use_fast_fed) {
+ feedl <<= static_cast<unsigned>(fast_profile->step_type);
+ dist = (scan_table.table.size() + 2 * fast_table.table.size());
+ // TODO read and decode REG_0xAB
+ dist += (reg->get8(0x5e) & 31);
+ dist += reg->get8(REG_FEDCNT);
+ } else {
feedl <<= static_cast<unsigned>(motor_profile.step_type);
- dist = scan_table.steps_count;
- if (has_flag(flags, MotorFlag::FEED)) {
+ dist = scan_table.table.size();
+ if (has_flag(flags, ScanFlag::FEEDING)) {
dist *= 2;
}
}
- DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist);
- /* check for overflow */
+ // check for overflow
if (dist < feedl) {
feedl -= dist;
} else {
@@ -442,13 +470,9 @@ static void gl846_init_motor_regs_scan(Genesys_Device* dev,
}
reg->set24(REG_FEEDL, feedl);
- DBG (DBG_io ,"%s: feedl=%d\n",__func__,feedl);
-
- r = sanei_genesys_get_address(reg, REG_0x0C);
- ccdlmt = (r->value & REG_0x0C_CCDLMT) + 1;
- r = sanei_genesys_get_address(reg, REG_0x1C);
- tgtime = 1 << (r->value & REG_0x1C_TGTIME);
+ unsigned ccdlmt = (reg->get8(REG_0x0C) & REG_0x0C_CCDLMT) + 1;
+ unsigned tgtime = 1 << (reg->get8(REG_0x1C) & REG_0x1C_TGTIME);
/* hi res motor speed GPIO */
/*
@@ -482,56 +506,31 @@ static void gl846_init_motor_regs_scan(Genesys_Device* dev,
dev->interface->write_register(REG_0x6C, val);
*/
- if(dev->model->gpio_id == GpioId::IMG101) {
- if (scan_yres == sensor.get_register_hwdpi(scan_yres)) {
- val=1;
- }
- else
- {
- val=0;
- }
- dev->interface->write_register(REG_0x7E, val);
- }
-
- min_restep = (scan_table.steps_count / step_multiplier) / 2 - 1;
+ unsigned min_restep = (scan_table.table.size() / step_multiplier) / 2 - 1;
if (min_restep < 1) {
min_restep = 1;
}
- r = sanei_genesys_get_address(reg, REG_FWDSTEP);
- r->value = min_restep;
- r = sanei_genesys_get_address(reg, REG_BWDSTEP);
- r->value = min_restep;
+ reg->set8(REG_FWDSTEP, min_restep);
+ reg->set8(REG_BWDSTEP, min_restep);
+
+ std::uint32_t z1, z2;
sanei_genesys_calculate_zmod(use_fast_fed,
- scan_exposure_time*ccdlmt*tgtime,
+ scan_exposure_time * ccdlmt * tgtime,
scan_table.table,
- scan_table.steps_count,
+ scan_table.table.size(),
feedl,
min_restep * step_multiplier,
&z1,
&z2);
- DBG(DBG_info, "%s: z1 = %d\n", __func__, z1);
reg->set24(REG_0x60, z1 | (static_cast<unsigned>(motor_profile.step_type) << (16 + REG_0x60S_STEPSEL)));
-
- DBG(DBG_info, "%s: z2 = %d\n", __func__, z2);
reg->set24(REG_0x63, z2 | (static_cast<unsigned>(motor_profile.step_type) << (16 + REG_0x63S_FSTPSEL)));
- r = sanei_genesys_get_address (reg, 0x1e);
- r->value &= 0xf0; /* 0 dummy lines */
- r->value |= scan_dummy; /* dummy lines */
-
- r = sanei_genesys_get_address(reg, REG_0x67);
- r->value = 0x7f;
+ reg->set8_mask(REG_0x1E, scan_dummy, 0x0f);
- r = sanei_genesys_get_address(reg, REG_0x68);
- r->value = 0x7f;
-
- reg->set8(REG_STEPNO, scan_table.steps_count / step_multiplier);
- reg->set8(REG_FASTNO, scan_table.steps_count / step_multiplier);
- reg->set8(REG_FSHDEC, scan_table.steps_count / step_multiplier);
- reg->set8(REG_FMOVNO, fast_table.steps_count / step_multiplier);
- reg->set8(REG_FMOVDEC, fast_table.steps_count / step_multiplier);
+ reg->set8(REG_0x67, 0x7f);
+ reg->set8(REG_0x68, 0x7f);
}
@@ -558,82 +557,69 @@ static void gl846_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
const ScanSession& session)
{
DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time);
- unsigned int dpihw;
- GenesysRegister *r;
-
- // resolution is divided according to ccd_pixels_per_system_pixel()
- unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel();
- DBG(DBG_io2, "%s: ccd_pixels_per_system_pixel=%d\n", __func__, ccd_pixels_per_system_pixel);
- // to manage high resolution device while keeping good low resolution scanning speed,
- // we make hardware dpi vary
- dpihw = sensor.get_register_hwdpi(session.params.xres * ccd_pixels_per_system_pixel);
- DBG(DBG_io2, "%s: dpihw=%d\n", __func__, dpihw);
-
- gl846_setup_sensor(dev, sensor, reg);
+ scanner_setup_sensor(*dev, sensor, *reg);
dev->cmd_set->set_fe(dev, sensor, AFE_SET);
/* enable shading */
regs_set_optical_off(dev->model->asic_type, *reg);
- r = sanei_genesys_get_address(reg, REG_0x01);
- r->value |= REG_0x01_SHDAREA;
+ reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA;
if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
- (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION))
+ has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) ||
+ session.use_host_side_calib)
{
- r->value &= ~REG_0x01_DVDSET;
- }
- else
- {
- r->value |= REG_0x01_DVDSET;
+ reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET;
+ } else {
+ reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET;
}
- r = sanei_genesys_get_address(reg, REG_0x03);
- r->value &= ~REG_0x03_AVEENB;
+ reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB;
sanei_genesys_set_lamp_power(dev, sensor, *reg,
!has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
+ reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA);
- /* BW threshold */
- r = sanei_genesys_get_address (reg, 0x2e);
- r->value = dev->settings.threshold;
- r = sanei_genesys_get_address (reg, 0x2f);
- r->value = dev->settings.threshold;
+ // BW threshold
+ reg->set8(0x2e, 0x7f);
+ reg->set8(0x2f, 0x7f);
/* monochrome / color scan */
- r = sanei_genesys_get_address(reg, REG_0x04);
switch (session.params.depth) {
case 8:
- r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
+ reg->find_reg(REG_0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
break;
case 16:
- r->value &= ~REG_0x04_LINEART;
- r->value |= REG_0x04_BITSET;
+ reg->find_reg(REG_0x04).value &= ~REG_0x04_LINEART;
+ reg->find_reg(REG_0x04).value |= REG_0x04_BITSET;
break;
}
- r->value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
+ reg->find_reg(REG_0x04).value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
if (session.params.channels == 1)
{
switch (session.params.color_filter)
{
case ColorFilter::RED:
- r->value |= 0x24;
+ reg->find_reg(REG_0x04).value |= 0x24;
break;
case ColorFilter::BLUE:
- r->value |= 0x2c;
+ reg->find_reg(REG_0x04).value |= 0x2c;
break;
case ColorFilter::GREEN:
- r->value |= 0x28;
+ reg->find_reg(REG_0x04).value |= 0x28;
break;
default:
break; // should not happen
}
} else {
- r->value |= 0x20; // mono
+ reg->find_reg(REG_0x04).value |= 0x20; // mono
}
- sanei_genesys_set_dpihw(*reg, sensor, dpihw);
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution,
+ session.params.channels,
+ session.params.scan_method);
+ sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw);
if (should_enable_gamma(session, sensor)) {
reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
@@ -644,38 +630,31 @@ static void gl846_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
/* CIS scanners can do true gray by setting LEDADD */
/* we set up LEDADD only when asked */
if (dev->model->is_cis) {
- r = sanei_genesys_get_address (reg, 0x87);
- r->value &= ~REG_0x87_LEDADD;
+ reg->find_reg(0x87).value &= ~REG_0x87_LEDADD;
+
if (session.enable_ledadd) {
- r->value |= REG_0x87_LEDADD;
+ reg->find_reg(0x87).value |= REG_0x87_LEDADD;
}
/* RGB weighting
- r = sanei_genesys_get_address (reg, 0x01);
- r->value &= ~REG_0x01_TRUEGRAY;
+ reg->find_reg(0x01).value &= ~REG_0x01_TRUEGRAY;
+
if (session.enable_ledadd))
{
- r->value |= REG_0x01_TRUEGRAY;
+ reg->find_reg(0x01).value |= REG_0x01_TRUEGRAY;
}*/
}
- unsigned dpiset = session.params.xres * ccd_pixels_per_system_pixel;
- reg->set16(REG_DPISET, dpiset);
- DBG(DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset);
-
+ reg->set16(REG_DPISET, sensor.register_dpiset);
reg->set16(REG_STRPIXEL, session.pixel_startx);
reg->set16(REG_ENDPIXEL, session.pixel_endx);
- build_image_pipeline(dev, session);
+ setup_image_pipeline(*dev, session);
/* MAXWD is expressed in 4 words unit */
// BUG: we shouldn't multiply by channels here
reg->set24(REG_MAXWD, (session.output_line_bytes_raw * session.params.channels >> 2));
-
reg->set16(REG_LPERIOD, exposure_time);
- DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time);
-
- r = sanei_genesys_get_address (reg, 0x34);
- r->value = sensor.dummy_pixel;
+ reg->set8(0x34, sensor.dummy_pixel);
}
void CommandSetGl846::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
@@ -685,13 +664,12 @@ void CommandSetGl846::init_regs_for_scan_session(Genesys_Device* dev, const Gene
DBG_HELPER(dbg);
session.assert_computed();
- int move;
int exposure_time;
int slope_dpi = 0;
- int dummy = 0;
- dummy = 3-session.params.channels;
+ // FIXME: on cis scanners we may want to scan at reduced resolution
+ int dummy = 0;
/* slope_dpi */
/* cis color scan is effectively a gray scan with 3 gray lines per color
@@ -705,46 +683,18 @@ void CommandSetGl846::init_regs_for_scan_session(Genesys_Device* dev, const Gene
slope_dpi = slope_dpi * (1 + dummy);
exposure_time = sensor.exposure_lperiod;
- const auto& motor_profile = sanei_genesys_get_motor_profile(*gl846_motor_profiles,
- dev->model->motor_id,
- exposure_time);
-
- DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time);
- DBG(DBG_info, "%s : scan_step_type=%d\n", __func__,
- static_cast<unsigned>(motor_profile.step_type));
+ const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure_time, session);
/* we enable true gray for cis scanners only, and just when doing
* scan since color calibration is OK for this mode
*/
gl846_init_optical_regs_scan(dev, sensor, reg, exposure_time, session);
-
-/*** motor parameters ***/
-
- /* add tl_y to base movement */
- move = session.params.starty;
- DBG(DBG_info, "%s: move=%d steps\n", __func__, move);
-
- MotorFlag mflags = MotorFlag::NONE;
- if (has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) {
- mflags |= MotorFlag::DISABLE_BUFFER_FULL_MOVE;
- }
- if (has_flag(session.params.flags, ScanFlag::FEEDING)) {
- mflags |= MotorFlag::FEED;
- }
- if (has_flag(session.params.flags, ScanFlag::REVERSE)) {
- mflags |= MotorFlag::REVERSE;
- }
-
- gl846_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure_time, slope_dpi,
- dev->model->is_cis ? session.output_line_count * session.params.channels
- : session.output_line_count,
- dummy, move, mflags);
+ gl846_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure_time, slope_dpi,
+ session.optical_line_count, dummy, session.params.starty,
+ session.params.flags);
/*** prepares data reordering ***/
- dev->read_buffer.clear();
- dev->read_buffer.alloc(session.buffer_size_read);
-
dev->read_active = true;
dev->session = session;
@@ -759,21 +709,50 @@ ScanSession CommandSetGl846::calculate_scan_session(const Genesys_Device* dev,
const Genesys_Sensor& sensor,
const Genesys_Settings& settings) const
{
- int start;
-
DBG(DBG_info, "%s ", __func__);
debug_dump(DBG_info, settings);
- /* start */
- start = static_cast<int>(dev->model->x_offset);
- start += static_cast<int>(settings.tl_x);
- start = static_cast<int>((start * sensor.optical_res) / MM_PER_INCH);
+ ScanFlag flags = ScanFlag::NONE;
+
+ unsigned move_dpi = dev->motor.base_ydpi;
+
+ float move = dev->model->y_offset;
+ if (settings.scan_method == ScanMethod::TRANSPARENCY ||
+ settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ // note: scanner_move_to_ta() function has already been called and the sensor is at the
+ // transparency adapter
+ if (!dev->ignore_offsets) {
+ move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta;
+ }
+ flags |= ScanFlag::USE_XPA;
+ } else {
+ if (!dev->ignore_offsets) {
+ move = dev->model->y_offset;
+ }
+ }
+
+ move = move + settings.tl_y;
+ move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
+ move -= dev->head_pos(ScanHeadId::PRIMARY);
+
+ float start = dev->model->x_offset;
+ if (settings.scan_method == ScanMethod::TRANSPARENCY ||
+ settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ start = dev->model->x_offset_ta;
+ } else {
+ start = dev->model->x_offset;
+ }
+
+ start = start + dev->settings.tl_x;
+ start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
ScanSession session;
session.params.xres = settings.xres;
session.params.yres = settings.yres;
- session.params.startx = start; // not used
- session.params.starty = 0; // not used
+ session.params.startx = static_cast<unsigned>(start);
+ session.params.starty = static_cast<unsigned>(move);
session.params.pixels = settings.pixels;
session.params.requested_pixels = settings.requested_pixels;
session.params.lines = settings.lines;
@@ -782,7 +761,8 @@ ScanSession CommandSetGl846::calculate_scan_session(const Genesys_Device* dev,
session.params.scan_method = settings.scan_method;
session.params.scan_mode = settings.scan_mode;
session.params.color_filter = settings.color_filter;
- session.params.flags = ScanFlag::NONE;
+ // backtracking isn't handled well, so don't enable it
+ session.params.flags = flags;
compute_session(dev, session, sensor);
@@ -809,24 +789,17 @@ void CommandSetGl846::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens
DBG_HELPER(dbg);
(void) sensor;
uint8_t val;
- GenesysRegister *r;
- /* XXX STEF XXX SCAN GPIO */
- /*
- val = dev->interface->read_register(REG_0x6C);
- dev->interface->write_register(REG_0x6C, val);
- */
+ if (reg->state.is_xpa_on && reg->state.is_lamp_on) {
+ dev->cmd_set->set_xpa_lamp_power(*dev, true);
+ }
- val = REG_0x0D_CLRLNCNT;
- dev->interface->write_register(REG_0x0D, val);
- val = REG_0x0D_CLRMCNT;
- dev->interface->write_register(REG_0x0D, val);
+ scanner_clear_scan_and_feed_counts(*dev);
val = dev->interface->read_register(REG_0x01);
val |= REG_0x01_SCAN;
dev->interface->write_register(REG_0x01, val);
- r = sanei_genesys_get_address (reg, REG_0x01);
- r->value = val;
+ reg->set8(REG_0x01, val);
scanner_start_action(*dev, start_motor);
@@ -841,6 +814,10 @@ void CommandSetGl846::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg,
(void) reg;
DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop);
+ if (reg->state.is_xpa_on) {
+ dev->cmd_set->set_xpa_lamp_power(*dev, false);
+ }
+
if (!dev->model->is_sheetfed) {
scanner_stop_action(*dev);
}
@@ -852,260 +829,72 @@ void CommandSetGl846::move_back_home(Genesys_Device* dev, bool wait_until_home)
scanner_move_back_home(*dev, wait_until_home);
}
-// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi
-// from very top of scanner
-void CommandSetGl846::search_start_position(Genesys_Device* dev) const
-{
- DBG_HELPER(dbg);
- int size;
- Genesys_Register_Set local_reg;
-
- int pixels = 600;
- int dpi = 300;
-
- local_reg = dev->reg;
-
- /* sets for a 200 lines * 600 pixels */
- /* normal scan with no shading */
-
- // FIXME: the current approach of doing search only for one resolution does not work on scanners
- // whith employ different sensors with potentially different settings.
- const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method);
-
- ScanSession session;
- session.params.xres = dpi;
- session.params.yres = dpi;
- session.params.startx = 0;
- session.params.starty = 0; /*we should give a small offset here~60 steps */
- session.params.pixels = 600;
- session.params.lines = dev->model->search_lines;
- session.params.depth = 8;
- session.params.channels = 1;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::GRAY;
- session.params.color_filter = ColorFilter::GREEN;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &local_reg, session);
-
- // send to scanner
- dev->interface->write_registers(local_reg);
-
- size = pixels * dev->model->search_lines;
-
- std::vector<uint8_t> data(size);
-
- begin_scan(dev, sensor, &local_reg, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("search_start_position");
- end_scan(dev, &local_reg, true);
- dev->reg = local_reg;
- return;
- }
-
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- sanei_genesys_read_data_from_scanner(dev, data.data(), size);
-
- if (DBG_LEVEL >= DBG_data) {
- sanei_genesys_write_pnm_file("gl846_search_position.pnm", data.data(), 8, 1, pixels,
- dev->model->search_lines);
- }
-
- end_scan(dev, &local_reg, true);
-
- /* update regs to copy ASIC internal state */
- dev->reg = local_reg;
-
- // TODO: find out where sanei_genesys_search_reference_point stores information,
- // and use that correctly
- for (auto& sensor_update :
- sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method))
- {
- sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels,
- dev->model->search_lines);
- }
-}
-
-// sets up register for coarse gain calibration
-// todo: check it for scanners using it
-void CommandSetGl846::init_regs_for_coarse_calibration(Genesys_Device* dev,
- const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs) const
-{
- DBG_HELPER(dbg);
-
- ScanSession session;
- session.params.xres = dev->settings.xres;
- session.params.yres = dev->settings.yres;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel();
- session.params.lines = 20;
- session.params.depth = 16;
- session.params.channels = dev->settings.get_channels();
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = dev->settings.scan_mode;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &regs, session);
-
- DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__,
- sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres);
-
- dev->interface->write_registers(regs);
-}
-
// init registers for shading calibration
void CommandSetGl846::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
- float move;
- dev->calib_channels = 3;
+ unsigned move_dpi = dev->motor.base_ydpi;
- /* initial calibration reg values */
- regs = dev->reg;
+ float calib_size_mm = 0;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ calib_size_mm = dev->model->y_size_calib_ta_mm;
+ } else {
+ calib_size_mm = dev->model->y_size_calib_mm;
+ }
- dev->calib_resolution = sensor.get_register_hwdpi(dev->settings.xres);
+ unsigned channels = 3;
+ unsigned resolution = sensor.shading_resolution;
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->calib_resolution,
- dev->calib_channels,
+ const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
- dev->calib_total_bytes_to_read = 0;
- dev->calib_lines = dev->model->shading_lines;
- if (dev->calib_resolution==4800) {
- dev->calib_lines *= 2;
- }
- dev->calib_pixels = (calib_sensor.sensor_pixels * dev->calib_resolution) /
- calib_sensor.optical_res;
- DBG(DBG_io, "%s: calib_lines = %zu\n", __func__, dev->calib_lines);
- DBG(DBG_io, "%s: calib_pixels = %zu\n", __func__, dev->calib_pixels);
+ float move = 0;
+ ScanFlag flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA |
+ ScanFlag::DISABLE_BUFFER_FULL_MOVE;
- /* this is aworkaround insufficent distance for slope
- * motor acceleration TODO special motor slope for shading */
- move=1;
- if(dev->calib_resolution<1200)
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
- move=40;
+ // note: scanner_move_to_ta() function has already been called and the sensor is at the
+ // transparency adapter
+ move = static_cast<int>(dev->model->y_offset_calib_white_ta - dev->model->y_offset_sensor_to_ta);
+ flags |= ScanFlag::USE_XPA;
+ } else {
+ move = static_cast<int>(dev->model->y_offset_calib_white);
}
+ move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
+
+ unsigned calib_lines = static_cast<unsigned>(calib_size_mm * resolution / MM_PER_INCH);
+
ScanSession session;
- session.params.xres = dev->calib_resolution;
- session.params.yres = dev->calib_resolution;
+ session.params.xres = resolution;
+ session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = static_cast<unsigned>(move);
- session.params.pixels = dev->calib_pixels;
- session.params.lines = dev->calib_lines;
+ session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
+ session.params.lines = calib_lines;
session.params.depth = 16;
- session.params.channels = dev->calib_channels;
+ session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::DISABLE_BUFFER_FULL_MOVE |
- ScanFlag::IGNORE_LINE_DISTANCE;
+ session.params.flags = flags;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
- dev->interface->write_registers(regs);
-
- /* we use GENESYS_FLAG_SHADING_REPARK */
+ /* we use ModelFlag::SHADING_REPARK */
dev->set_head_pos_zero(ScanHeadId::PRIMARY);
-}
-
-/** @brief set up registers for the actual scan
- */
-void CommandSetGl846::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const
-{
- DBG_HELPER(dbg);
- float move;
- int move_dpi;
- float start;
-
- debug_dump(DBG_info, dev->settings);
- /* steps to move to reach scanning area:
- - first we move to physical start of scanning
- either by a fixed steps amount from the black strip
- or by a fixed amount from parking position,
- minus the steps done during shading calibration
- - then we move by the needed offset whitin physical
- scanning area
-
- assumption: steps are expressed at maximum motor resolution
-
- we need:
- float y_offset;
- float y_size;
- float y_offset_calib;
- mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */
-
- /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is
- relative from origin, else, it is from parking position */
-
- move_dpi = dev->motor.base_ydpi;
-
- move = static_cast<float>(dev->model->y_offset);
- move = static_cast<float>(move + dev->settings.tl_y);
- move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
- move -= dev->head_pos(ScanHeadId::PRIMARY);
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
-
- /* fast move to scan area */
- /* we don't move fast the whole distance since it would involve
- * computing acceleration/deceleration distance for scan
- * resolution. So leave a remainder for it so scan makes the final
- * move tuning */
- if (dev->settings.get_channels() * dev->settings.yres >= 600 && move > 700) {
- scanner_move(*dev, dev->model->default_method, static_cast<unsigned>(move - 500),
- Direction::FORWARD);
- move=500;
- }
-
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
-
- /* start */
- start = static_cast<float>(dev->model->x_offset);
- start = static_cast<float>(start + dev->settings.tl_x);
- start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
-
- ScanSession session;
- session.params.xres = dev->settings.xres;
- session.params.yres = dev->settings.yres;
- session.params.startx = static_cast<unsigned>(start);
- session.params.starty = static_cast<unsigned>(move);
- session.params.pixels = dev->settings.pixels;
- session.params.requested_pixels = dev->settings.requested_pixels;
- session.params.lines = dev->settings.lines;
- session.params.depth = dev->settings.depth;
- session.params.channels = dev->settings.get_channels();
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = dev->settings.scan_mode;
- session.params.color_filter = dev->settings.color_filter;
- // backtracking isn't handled well, so don't enable it
- session.params.flags = ScanFlag::DISABLE_BUFFER_FULL_MOVE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &dev->reg, session);
+ dev->calib_session = session;
}
-
/**
* Send shading calibration data. The buffer is considered to always hold values
* for all the channels.
@@ -1114,39 +903,24 @@ void CommandSetGl846::send_shading_data(Genesys_Device* dev, const Genesys_Senso
uint8_t* data, int size) const
{
DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size);
- uint32_t addr, length, i, x, factor, pixels;
- uint32_t dpiset, dpihw;
+ std::uint32_t addr, i;
uint8_t val,*ptr,*src;
- /* shading data is plit in 3 (up to 5 with IR) areas
- write(0x10014000,0x00000dd8)
- URB 23429 bulk_out len 3544 wrote 0x33 0x10 0x....
- write(0x1003e000,0x00000dd8)
- write(0x10068000,0x00000dd8)
- */
- length = static_cast<uint32_t>(size / 3);
- unsigned strpixel = dev->session.pixel_startx;
- unsigned endpixel = dev->session.pixel_endx;
-
- /* compute deletion factor */
- dpiset = dev->reg.get16(REG_DPISET);
- dpihw = sensor.get_register_hwdpi(dpiset);
- factor=dpihw/dpiset;
- DBG(DBG_io2, "%s: factor=%d\n", __func__, factor);
-
- pixels=endpixel-strpixel;
+ unsigned length = static_cast<unsigned>(size / 3);
- /* since we're using SHDAREA, substract startx coordinate from shading */
- strpixel -= (sensor.ccd_start_xoffset * 600) / sensor.optical_res;
+ // we're using SHDAREA, thus we only need to upload part of the line
+ unsigned offset = dev->session.pixel_count_ratio.apply(
+ dev->session.params.startx * sensor.full_resolution / dev->session.params.xres);
+ unsigned pixels = dev->session.pixel_count_ratio.apply(dev->session.optical_pixels_raw);
- /* turn pixel value into bytes 2x16 bits words */
- strpixel*=2*2;
- pixels*=2*2;
+ // turn pixel value into bytes 2x16 bits words
+ offset *= 2 * 2;
+ pixels *= 2 * 2;
- dev->interface->record_key_value("shading_offset", std::to_string(strpixel));
+ dev->interface->record_key_value("shading_offset", std::to_string(offset));
dev->interface->record_key_value("shading_pixels", std::to_string(pixels));
dev->interface->record_key_value("shading_length", std::to_string(length));
- dev->interface->record_key_value("shading_factor", std::to_string(factor));
+ dev->interface->record_key_value("shading_factor", std::to_string(sensor.shading_factor));
std::vector<uint8_t> buffer(pixels, 0);
@@ -1163,10 +937,9 @@ void CommandSetGl846::send_shading_data(Genesys_Device* dev, const Genesys_Senso
ptr = buffer.data();
/* iterate on both sensor segment */
- for(x=0;x<pixels;x+=4*factor)
- {
- /* coefficient source */
- src=(data+strpixel+i*length)+x;
+ for (unsigned x = 0; x < pixels; x += 4 * sensor.shading_factor) {
+ // coefficient source
+ src = (data + offset + i * length) + x;
/* coefficient copy */
ptr[0]=src[0];
@@ -1192,166 +965,7 @@ void CommandSetGl846::send_shading_data(Genesys_Device* dev, const Genesys_Senso
SensorExposure CommandSetGl846::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
- DBG_HELPER(dbg);
- int num_pixels;
- int total_size;
- int used_res;
- int i, j;
- int val;
- int channels;
- int avg[3], top[3], bottom[3];
- int turn;
- uint16_t exp[3];
-
- float move = static_cast<float>(dev->model->y_offset_calib_white);
- move = static_cast<float>((move * (dev->motor.base_ydpi / 4)) / MM_PER_INCH);
- if(move>20)
- {
- scanner_move(*dev, dev->model->default_method, static_cast<unsigned>(move),
- Direction::FORWARD);
- }
- DBG(DBG_io, "%s: move=%f steps\n", __func__, move);
-
- /* offset calibration is always done in color mode */
- channels = 3;
- used_res = sensor.get_register_hwdpi(dev->settings.xres);
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, used_res, channels,
- dev->settings.scan_method);
- num_pixels = (calib_sensor.sensor_pixels * used_res) / calib_sensor.optical_res;
-
- /* initial calibration reg values */
- regs = dev->reg;
-
- ScanSession session;
- session.params.xres = used_res;
- session.params.yres = used_res;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = num_pixels;
- session.params.lines = 1;
- session.params.depth = 16;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, calib_sensor);
-
- init_regs_for_scan_session(dev, calib_sensor, &regs, session);
-
- total_size = num_pixels * channels * (session.params.depth / 8) * 1;
- std::vector<uint8_t> line(total_size);
-
- /* initial loop values and boundaries */
- exp[0] = calib_sensor.exposure.red;
- exp[1] = calib_sensor.exposure.green;
- exp[2] = calib_sensor.exposure.blue;
-
- bottom[0]=29000;
- bottom[1]=29000;
- bottom[2]=29000;
-
- top[0]=41000;
- top[1]=51000;
- top[2]=51000;
-
- turn = 0;
-
- /* no move during led calibration */
- sanei_genesys_set_motor_power(regs, false);
- bool acceptable = false;
- do
- {
- // set up exposure
- regs.set16(REG_EXPR, exp[0]);
- regs.set16(REG_EXPG, exp[1]);
- regs.set16(REG_EXPB, exp[2]);
-
- // write registers and scan data
- dev->interface->write_registers(regs);
-
- DBG(DBG_info, "%s: starting line reading\n", __func__);
- begin_scan(dev, calib_sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("led_calibration");
- scanner_stop_action(*dev);
- move_back_home(dev, true);
- return calib_sensor.exposure;
- }
-
- sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
-
- // stop scanning
- scanner_stop_action(*dev);
-
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[30];
- std::snprintf(fn, 30, "gl846_led_%02d.pnm", turn);
- sanei_genesys_write_pnm_file(fn, line.data(), session.params.depth,
- channels, num_pixels, 1);
- }
-
- /* compute average */
- for (j = 0; j < channels; j++)
- {
- avg[j] = 0;
- for (i = 0; i < num_pixels; i++)
- {
- if (dev->model->is_cis)
- val =
- line[i * 2 + j * 2 * num_pixels + 1] * 256 +
- line[i * 2 + j * 2 * num_pixels];
- else
- val =
- line[i * 2 * channels + 2 * j + 1] * 256 +
- line[i * 2 * channels + 2 * j];
- avg[j] += val;
- }
-
- avg[j] /= num_pixels;
- }
-
- DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]);
-
- /* check if exposure gives average within the boundaries */
- acceptable = true;
- for(i=0;i<3;i++)
- {
- if(avg[i]<bottom[i])
- {
- exp[i]=(exp[i]*bottom[i])/avg[i];
- acceptable = false;
- }
- if(avg[i]>top[i])
- {
- exp[i]=(exp[i]*top[i])/avg[i];
- acceptable = false;
- }
- }
-
- turn++;
- }
- while (!acceptable && turn < 100);
-
- DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]);
-
- // set these values as final ones for scan
- dev->reg.set16(REG_EXPR, exp[0]);
- dev->reg.set16(REG_EXPG, exp[1]);
- dev->reg.set16(REG_EXPB, exp[2]);
-
- /* go back home */
- if(move>20)
- {
- move_back_home(dev, true);
- }
-
- return { exp[0], exp[1], exp[2] };
+ return scanner_led_calibration(*dev, sensor, regs);
}
/**
@@ -1360,29 +974,10 @@ SensorExposure CommandSetGl846::led_calibration(Genesys_Device* dev, const Genes
static void gl846_init_gpio(Genesys_Device* dev)
{
DBG_HELPER(dbg);
- int idx=0;
-
- /* search GPIO profile */
- while (gpios[idx].gpio_id != GpioId::UNKNOWN && dev->model->gpio_id != gpios[idx].gpio_id) {
- idx++;
- }
- if (gpios[idx].gpio_id == GpioId::UNKNOWN)
+ apply_registers_ordered(dev->gpo.regs, { 0x6e, 0x6f }, [&](const GenesysRegisterSetting& reg)
{
- throw SaneException("failed to find GPIO profile for sensor_id=%d",
- static_cast<unsigned>(dev->model->sensor_id));
- }
-
- dev->interface->write_register(REG_0xA7, gpios[idx].ra7);
- dev->interface->write_register(REG_0xA6, gpios[idx].ra6);
-
- dev->interface->write_register(REG_0x6B, gpios[idx].r6b);
- dev->interface->write_register(REG_0x6C, gpios[idx].r6c);
- dev->interface->write_register(REG_0x6D, gpios[idx].r6d);
- dev->interface->write_register(REG_0x6E, gpios[idx].r6e);
- dev->interface->write_register(REG_0x6F, gpios[idx].r6f);
-
- dev->interface->write_register(REG_0xA8, gpios[idx].ra8);
- dev->interface->write_register(REG_0xA9, gpios[idx].ra9);
+ dev->interface->write_register(reg.address, reg.value);
+ });
}
/**
@@ -1391,32 +986,11 @@ static void gl846_init_gpio(Genesys_Device* dev)
static void gl846_init_memory_layout(Genesys_Device* dev)
{
DBG_HELPER(dbg);
- int idx = 0, i;
- uint8_t val;
-
- /* point to per model memory layout */
- idx = 0;
- while (layouts[idx].model != nullptr && strcmp(dev->model->name,layouts[idx].model)!=0) {
- if(strcmp(dev->model->name,layouts[idx].model)!=0)
- idx++;
- }
- if (layouts[idx].model == nullptr) {
- throw SaneException("failed to find memory layout for model %s", dev->model->name);
- }
- /* CLKSET and DRAMSEL */
- val = layouts[idx].dramsel;
- dev->interface->write_register(REG_0x0B, val);
- dev->reg.find_reg(0x0b).value = val;
+ // prevent further writings by bulk write register
+ dev->reg.remove_reg(0x0b);
- /* prevent further writings by bulk write register */
- dev->reg.remove_reg(0x0b);
-
- /* setup base address for shading and scanned data. */
- for(i=0;i<10;i++)
- {
- dev->interface->write_register(0xe0+i, layouts[idx].rx[i]);
- }
+ apply_reg_settings_to_device_write_only(*dev, dev->memory_layout.regs);
}
/* *
@@ -1433,15 +1007,14 @@ void CommandSetGl846::asic_boot(Genesys_Device* dev, bool cold) const
dev->interface->write_register(0x0e, 0x00);
}
- if(dev->usb_mode == 1)
- {
- val = 0x14;
- }
- else
- {
- val = 0x11;
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICBOOK_3800) {
+ if (dev->usb_mode == 1) {
+ val = 0x14;
+ } else {
+ val = 0x11;
+ }
+ dev->interface->write_0x8c(0x0f, val);
}
- dev->interface->write_0x8c(0x0f, val);
// test CHKVER
val = dev->interface->read_register(REG_0x40);
@@ -1450,18 +1023,11 @@ void CommandSetGl846::asic_boot(Genesys_Device* dev, bool cold) const
DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val);
}
- /* Set default values for registers */
- gl846_init_registers (dev);
+ gl846_init_registers (dev);
// Write initial registers
dev->interface->write_registers(dev->reg);
- /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */
- val = dev->reg.find_reg(0x0b).value & REG_0x0B_DRAMSEL;
- val = (val | REG_0x0B_ENBDRAM);
- dev->interface->write_register(REG_0x0B, val);
- dev->reg.find_reg(0x0b).value = val;
-
/* CIS_LINE */
if (dev->model->is_cis)
{
@@ -1470,8 +1036,15 @@ void CommandSetGl846::asic_boot(Genesys_Device* dev, bool cold) const
}
// set up clocks
- dev->interface->write_0x8c(0x10, 0x0e);
- dev->interface->write_0x8c(0x13, 0x0e);
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ dev->interface->write_0x8c(0x10, 0x0c);
+ dev->interface->write_0x8c(0x13, 0x0c);
+ } else {
+ dev->interface->write_0x8c(0x10, 0x0e);
+ dev->interface->write_0x8c(0x13, 0x0e);
+ }
// setup gpio
gl846_init_gpio(dev);
@@ -1492,7 +1065,7 @@ void CommandSetGl846::init(Genesys_Device* dev) const
DBG_INIT ();
DBG_HELPER(dbg);
- sanei_genesys_asic_init(dev, 0);
+ sanei_genesys_asic_init(dev);
}
void CommandSetGl846::update_hardware_sensors(Genesys_Scanner* s) const
@@ -1529,512 +1102,16 @@ void CommandSetGl846::update_home_sensor_gpio(Genesys_Device& dev) const
dev.interface->write_register(REG_0x6C, val);
}
-/** @brief 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 CommandSetGl846::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward,
- bool black) const
-{
- DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse");
- unsigned int pixels, lines, channels;
- Genesys_Register_Set local_reg;
- size_t size;
- unsigned int pass, count, found, x, y;
- char title[80];
-
- set_fe(dev, sensor, AFE_SET);
-
- scanner_stop_action(*dev);
-
- // set up for a gray scan at lowest dpi
- const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method);
- unsigned dpi = resolution_settings.get_min_resolution_x();
- channels = 1;
- /* 10 MM */
- /* lines = (10 * dpi) / MM_PER_INCH; */
- /* shading calibation is done with dev->motor.base_ydpi */
- lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi;
- pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res;
-
- dev->set_head_pos_zero(ScanHeadId::PRIMARY);
-
- local_reg = dev->reg;
-
- ScanSession session;
- session.params.xres = dpi;
- session.params.yres = dpi;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = pixels;
- session.params.lines = lines;
- session.params.depth = 8;
- session.params.channels = channels;
- session.params.scan_mode = ScanColorMode::GRAY;
- session.params.color_filter = ColorFilter::RED;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA;
- if (!forward) {
- session.params.flags |= ScanFlag::REVERSE;
- }
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &local_reg, session);
-
- size = pixels * channels * lines * (session.params.depth / 8);
- std::vector<uint8_t> data(size);
-
- dev->interface->write_registers(local_reg);
-
- begin_scan(dev, sensor, &local_reg, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("search_strip");
- scanner_stop_action(*dev);
- return;
- }
-
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- sanei_genesys_read_data_from_scanner(dev, data.data(), size);
-
- scanner_stop_action(*dev);
-
- pass = 0;
- if (DBG_LEVEL >= DBG_data)
- {
- std::sprintf(title, "gl846_search_strip_%s_%s%02d.pnm",
- black ? "black" : "white", forward ? "fwd" : "bwd", pass);
- sanei_genesys_write_pnm_file(title, data.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- /* loop until strip is found or maximum pass number done */
- found = 0;
- while (pass < 20 && !found)
- {
- dev->interface->write_registers(local_reg);
-
- // now start scan
- begin_scan(dev, sensor, &local_reg, true);
-
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- sanei_genesys_read_data_from_scanner(dev, data.data(), size);
-
- scanner_stop_action(*dev);
-
- if (DBG_LEVEL >= DBG_data)
- {
- std::sprintf(title, "gl846_search_strip_%s_%s%02d.pnm",
- black ? "black" : "white", forward ? "fwd" : "bwd", pass);
- sanei_genesys_write_pnm_file(title, data.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- /* search data to find black strip */
- /* when searching forward, we only need one line of the searched color since we
- * will scan forward. But when doing backward search, we need all the area of the
- * same color */
- if (forward)
- {
- for (y = 0; y < lines && !found; y++)
- {
- count = 0;
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < pixels; x++)
- {
- /* when searching for black, detect white pixels */
- if (black && data[y * pixels + x] > 90)
- {
- count++;
- }
- /* when searching for white, detect black pixels */
- if (!black && data[y * pixels + x] < 60)
- {
- count++;
- }
- }
-
- /* at end of line, if count >= 3%, line is not fully of the desired color
- * so we must go to next line of the buffer */
- /* count*100/pixels < 3 */
- if ((count * 100) / pixels < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__,
- pass, y);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
- (100 * count) / pixels);
- }
- }
- }
- else /* since calibration scans are done forward, we need the whole area
- to be of the required color when searching backward */
- {
- count = 0;
- for (y = 0; y < lines; y++)
- {
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < pixels; x++)
- {
- /* when searching for black, detect white pixels */
- if (black && data[y * pixels + x] > 90)
- {
- count++;
- }
- /* when searching for white, detect black pixels */
- if (!black && data[y * pixels + x] < 60)
- {
- count++;
- }
- }
- }
-
- /* at end of area, if count >= 3%, area is not fully of the desired color
- * so we must go to next buffer */
- if ((count * 100) / (pixels * lines) < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
- (100 * count) / pixels);
- }
- }
- pass++;
- }
-
- if (found)
- {
- DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white");
- }
- else
- {
- throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white");
- }
-}
-
-/**
- * average dark pixels of a 8 bits scan
- */
-static int
-dark_average (uint8_t * data, unsigned int pixels, unsigned int lines,
- unsigned int channels, unsigned int black)
-{
- unsigned int i, j, k, average, count;
- unsigned int avg[3];
- uint8_t val;
-
- /* computes average value on black margin */
- for (k = 0; k < channels; k++)
- {
- avg[k] = 0;
- count = 0;
- for (i = 0; i < lines; i++)
- {
- for (j = 0; j < black; j++)
- {
- val = data[i * channels * pixels + j + k];
- avg[k] += val;
- count++;
- }
- }
- if (count)
- avg[k] /= count;
- DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]);
- }
- average = 0;
- for (i = 0; i < channels; i++)
- average += avg[i];
- average /= channels;
- DBG(DBG_info, "%s: average = %d\n", __func__, average);
- return average;
-}
-
void CommandSetGl846::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
- DBG_HELPER(dbg);
- unsigned channels;
- int pass = 0, avg, total_size;
- int topavg, bottomavg, lines;
- int top, bottom, black_pixels, pixels;
-
- // no gain nor offset for AKM AFE
- uint8_t reg04 = dev->interface->read_register(REG_0x04);
- if ((reg04 & REG_0x04_FESET) == 0x02) {
- return;
- }
-
- /* offset calibration is always done in color mode */
- channels = 3;
- dev->calib_pixels = sensor.sensor_pixels;
- lines=1;
- pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
- black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res;
- DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
-
- ScanSession session;
- session.params.xres = sensor.optical_res;
- session.params.yres = sensor.optical_res;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = pixels;
- session.params.lines = lines;
- session.params.depth = 8;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &regs, session);
-
- sanei_genesys_set_motor_power(regs, false);
-
- total_size = pixels * channels * lines * (session.params.depth / 8);
-
- std::vector<uint8_t> first_line(total_size);
- std::vector<uint8_t> second_line(total_size);
-
- /* init gain */
- dev->frontend.set_gain(0, 0);
- dev->frontend.set_gain(1, 0);
- dev->frontend.set_gain(2, 0);
-
- /* scan with no move */
- bottom = 10;
- dev->frontend.set_offset(0, bottom);
- dev->frontend.set_offset(1, bottom);
- dev->frontend.set_offset(2, bottom);
-
- set_fe(dev, sensor, AFE_SET);
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting first line reading\n", __func__);
- begin_scan(dev, sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("offset_calibration");
- return;
- }
-
- sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size);
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[30];
- std::snprintf(fn, 30, "gl846_offset%03d.pnm", bottom);
- sanei_genesys_write_pnm_file(fn, first_line.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels);
- DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg);
-
- /* now top value */
- top = 255;
- dev->frontend.set_offset(0, top);
- dev->frontend.set_offset(1, top);
- dev->frontend.set_offset(2, top);
- set_fe(dev, sensor, AFE_SET);
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting second line reading\n", __func__);
- begin_scan(dev, sensor, &regs, true);
- sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
-
- topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
- DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg);
-
- /* loop until acceptable level */
- while ((pass < 32) && (top - bottom > 1))
- {
- pass++;
-
- /* settings for new scan */
- dev->frontend.set_offset(0, (top + bottom) / 2);
- dev->frontend.set_offset(1, (top + bottom) / 2);
- dev->frontend.set_offset(2, (top + bottom) / 2);
-
- // scan with no move
- set_fe(dev, sensor, AFE_SET);
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting second line reading\n", __func__);
- begin_scan(dev, sensor, &regs, true);
- sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
-
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[30];
- std::snprintf(fn, 30, "gl846_offset%03d.pnm", dev->frontend.get_offset(1));
- sanei_genesys_write_pnm_file(fn, second_line.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
- DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1));
-
- /* compute new boundaries */
- if (topavg == avg)
- {
- topavg = avg;
- top = dev->frontend.get_offset(1);
- }
- else
- {
- bottomavg = avg;
- bottom = dev->frontend.get_offset(1);
- }
- }
- DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
- dev->frontend.get_offset(0),
- dev->frontend.get_offset(1),
- dev->frontend.get_offset(2));
+ scanner_offset_calibration(*dev, sensor, regs);
}
void CommandSetGl846::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const
{
- DBG_HELPER(dbg);
- int pixels;
- int total_size;
- int i, j, channels;
- int max[3];
- float gain[3],coeff;
- int val, code, lines;
-
- DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi);
-
- // no gain nor offset for AKM AFE
- uint8_t reg04 = dev->interface->read_register(REG_0x04);
- if ((reg04 & REG_0x04_FESET) == 0x02) {
- return;
- }
-
- /* coarse gain calibration is always done in color mode */
- channels = 3;
-
- /* follow CKSEL */
- if(dev->settings.xres<sensor.optical_res)
- {
- coeff = 0.9f;
- }
- else
- {
- coeff=1.0;
- }
- lines=10;
- pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
-
- ScanSession session;
- session.params.xres = sensor.optical_res;
- session.params.yres = sensor.optical_res;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = pixels;
- session.params.lines = lines;
- session.params.depth = 8;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- try {
- init_regs_for_scan_session(dev, sensor, &regs, session);
- } catch (...) {
- catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); });
- throw;
- }
-
- sanei_genesys_set_motor_power(regs, false);
-
- dev->interface->write_registers(regs);
-
- total_size = pixels * channels * (16 / session.params.depth) * lines;
-
- std::vector<uint8_t> line(total_size);
-
- set_fe(dev, sensor, AFE_SET);
- begin_scan(dev, sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("coarse_gain_calibration");
- scanner_stop_action(*dev);
- move_back_home(dev, true);
- return;
- }
-
- sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
-
- if (DBG_LEVEL >= DBG_data) {
- sanei_genesys_write_pnm_file("gl846_gain.pnm", line.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- /* average value on each channel */
- for (j = 0; j < channels; j++)
- {
- max[j] = 0;
- for (i = pixels/4; i < (pixels*3/4); i++)
- {
- if (dev->model->is_cis)
- val = line[i + j * pixels];
- else
- val = line[i * channels + j];
-
- max[j] += val;
- }
- max[j] = max[j] / (pixels/2);
-
- gain[j] = (static_cast<float>(sensor.gain_white_ref) * coeff) / max[j];
-
- /* turn logical gain value into gain code, checking for overflow */
- code = static_cast<int>(283 - 208 / gain[j]);
- if (code > 255)
- code = 255;
- else if (code < 0)
- code = 0;
- dev->frontend.set_gain(j, code);
-
- DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j],
- dev->frontend.get_gain(j));
- }
-
- if (dev->model->is_cis) {
- uint8_t gain0 = dev->frontend.get_gain(0);
- if (gain0 > dev->frontend.get_gain(1)) {
- gain0 = dev->frontend.get_gain(1);
- }
- if (gain0 > dev->frontend.get_gain(2)) {
- gain0 = dev->frontend.get_gain(2);
- }
- dev->frontend.set_gain(0, gain0);
- dev->frontend.set_gain(1, gain0);
- dev->frontend.set_gain(2, gain0);
- }
-
- scanner_stop_action(*dev);
-
- move_back_home(dev, true);
+ scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
}
bool CommandSetGl846::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
@@ -2044,14 +1121,11 @@ bool CommandSetGl846::needs_home_before_init_regs_for_scan(Genesys_Device* dev)
}
void CommandSetGl846::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs, int* channels,
- int* total_size) const
+ Genesys_Register_Set* regs) const
{
(void) dev;
(void) sensor;
(void) regs;
- (void) channels;
- (void) total_size;
throw SaneException("not implemented");
}
@@ -2083,16 +1157,5 @@ void CommandSetGl846::eject_document(Genesys_Device* dev) const
throw SaneException("not implemented");
}
-void CommandSetGl846::move_to_ta(Genesys_Device* dev) const
-{
- (void) dev;
- throw SaneException("not implemented");
-}
-
-std::unique_ptr<CommandSet> create_gl846_cmd_set()
-{
- return std::unique_ptr<CommandSet>(new CommandSetGl846{});
-}
-
} // namespace gl846
} // namespace genesys
diff --git a/backend/genesys/gl846.h b/backend/genesys/gl846.h
index 258015a..f794a01 100644
--- a/backend/genesys/gl846.h
+++ b/backend/genesys/gl846.h
@@ -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,17 +60,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs, int* channels,
- int* total_size) const override;
-
- 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_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@@ -161,8 +80,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;
@@ -178,8 +95,6 @@ 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;
@@ -188,11 +103,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,
int size) const override;
diff --git a/backend/genesys/gl846_registers.h b/backend/genesys/gl846_registers.h
index 39b3029..e4a8ac5 100644
--- a/backend/genesys/gl846_registers.h
+++ b/backend/genesys/gl846_registers.h
@@ -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;
diff --git a/backend/genesys/gl847.cpp b/backend/genesys/gl847.cpp
index cb0b527..f8f6b1c 100644
--- a/backend/genesys/gl847.cpp
+++ b/backend/genesys/gl847.cpp
@@ -56,39 +56,12 @@ namespace gl847 {
/**
* compute the step multiplier used
*/
-static int
-gl847_get_step_multiplier (Genesys_Register_Set * regs)
+static unsigned gl847_get_step_multiplier (Genesys_Register_Set * regs)
{
- GenesysRegister *r = sanei_genesys_get_address(regs, 0x9d);
- int value = 1;
- if (r != nullptr)
- {
- value = (r->value & 0x0f)>>1;
- value = 1 << value;
- }
- DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value);
- return value;
+ unsigned value = (regs->get8(0x9d) & 0x0f) >> 1;
+ return 1 << value;
}
-/** @brief sensor specific settings
-*/
-static void gl847_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs)
-{
- DBG_HELPER(dbg);
-
- for (const auto& reg : sensor.custom_regs) {
- regs->set8(reg.address, reg.value);
- }
-
- regs->set16(REG_EXPR, sensor.exposure.red);
- regs->set16(REG_EXPG, sensor.exposure.green);
- regs->set16(REG_EXPB, sensor.exposure.blue);
-
- dev->segment_order = sensor.segment_order;
-}
-
-
/** @brief set all registers to default values .
* This function is called only once at the beginning and
* fills register startup values for registers reused across scans.
@@ -111,30 +84,49 @@ gl847_init_registers (Genesys_Device * dev)
dev->reg.clear();
dev->reg.init_reg(0x01, 0x82);
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ dev->reg.init_reg(0x01, 0x40);
+ }
dev->reg.init_reg(0x02, 0x18);
dev->reg.init_reg(0x03, 0x50);
dev->reg.init_reg(0x04, 0x12);
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ dev->reg.init_reg(0x04, 0x20);
+ }
dev->reg.init_reg(0x05, 0x80);
dev->reg.init_reg(0x06, 0x50); // FASTMODE + POWERBIT
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ dev->reg.init_reg(0x06, 0xf8);
+ }
dev->reg.init_reg(0x08, 0x10);
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ dev->reg.init_reg(0x08, 0x20);
+ }
dev->reg.init_reg(0x09, 0x01);
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ dev->reg.init_reg(0x09, 0x00);
+ }
dev->reg.init_reg(0x0a, 0x00);
dev->reg.init_reg(0x0b, 0x01);
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ dev->reg.init_reg(0x0b, 0x6b);
+ }
dev->reg.init_reg(0x0c, 0x02);
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ dev->reg.init_reg(0x0c, 0x00);
+ }
// LED exposures
- dev->reg.init_reg(0x10, 0x00);
- dev->reg.init_reg(0x11, 0x00);
- dev->reg.init_reg(0x12, 0x00);
- dev->reg.init_reg(0x13, 0x00);
- dev->reg.init_reg(0x14, 0x00);
- dev->reg.init_reg(0x15, 0x00);
+ dev->reg.init_reg(0x10, 0x00); // exposure, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x11, 0x00); // exposure, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x12, 0x00); // exposure, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x13, 0x00); // exposure, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x14, 0x00); // exposure, overwritten in scanner_setup_sensor() below
+ dev->reg.init_reg(0x15, 0x00); // exposure, overwritten in scanner_setup_sensor() below
dev->reg.init_reg(0x16, 0x10); // SENSOR_DEF
dev->reg.init_reg(0x17, 0x08); // SENSOR_DEF
dev->reg.init_reg(0x18, 0x00); // SENSOR_DEF
-
- // EXPDMY
dev->reg.init_reg(0x19, 0x50); // SENSOR_DEF
dev->reg.init_reg(0x1a, 0x34); // SENSOR_DEF
@@ -142,32 +134,40 @@ gl847_init_registers (Genesys_Device * dev)
dev->reg.init_reg(0x1c, 0x02); // SENSOR_DEF
dev->reg.init_reg(0x1d, 0x04); // SENSOR_DEF
dev->reg.init_reg(0x1e, 0x10);
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ dev->reg.init_reg(0x1e, 0xf0);
+ }
dev->reg.init_reg(0x1f, 0x04);
- dev->reg.init_reg(0x20, 0x02);
- dev->reg.init_reg(0x21, 0x10);
- dev->reg.init_reg(0x22, 0x7f);
- dev->reg.init_reg(0x23, 0x7f);
- dev->reg.init_reg(0x24, 0x10);
- dev->reg.init_reg(0x25, 0x00);
- dev->reg.init_reg(0x26, 0x00);
- dev->reg.init_reg(0x27, 0x00);
- dev->reg.init_reg(0x2c, 0x09);
- dev->reg.init_reg(0x2d, 0x60);
- dev->reg.init_reg(0x2e, 0x80);
- dev->reg.init_reg(0x2f, 0x80);
- dev->reg.init_reg(0x30, 0x00);
- dev->reg.init_reg(0x31, 0x10);
- dev->reg.init_reg(0x32, 0x15);
- dev->reg.init_reg(0x33, 0x0e);
- dev->reg.init_reg(0x34, 0x40);
- dev->reg.init_reg(0x35, 0x00);
- dev->reg.init_reg(0x36, 0x2a);
- dev->reg.init_reg(0x37, 0x30);
- dev->reg.init_reg(0x38, 0x2a);
- dev->reg.init_reg(0x39, 0xf8);
- dev->reg.init_reg(0x3d, 0x00);
- dev->reg.init_reg(0x3e, 0x00);
- dev->reg.init_reg(0x3f, 0x00);
+ dev->reg.init_reg(0x20, 0x02); // BUFSEL: buffer full condition
+ dev->reg.init_reg(0x21, 0x10); // STEPNO: set during motor setup
+ dev->reg.init_reg(0x22, 0x7f); // FWDSTEP: set during motor setup
+ dev->reg.init_reg(0x23, 0x7f); // BWDSTEP: set during motor setup
+ dev->reg.init_reg(0x24, 0x10); // FASTNO: set during motor setup
+ dev->reg.init_reg(0x25, 0x00); // LINCNT: set during motor setup
+ dev->reg.init_reg(0x26, 0x00); // LINCNT: set during motor setup
+ dev->reg.init_reg(0x27, 0x00); // LINCNT: set during motor setup
+
+ dev->reg.init_reg(0x2c, 0x09); // DPISET: set during sensor setup
+ dev->reg.init_reg(0x2d, 0x60); // DPISET: set during sensor setup
+
+ dev->reg.init_reg(0x2e, 0x80); // BWHI: black/white low threshdold
+ dev->reg.init_reg(0x2f, 0x80); // BWLOW: black/white low threshold
+
+ dev->reg.init_reg(0x30, 0x00); // STRPIXEL: set during sensor setup
+ dev->reg.init_reg(0x31, 0x10); // STRPIXEL: set during sensor setup
+ dev->reg.init_reg(0x32, 0x15); // ENDPIXEL: set during sensor setup
+ dev->reg.init_reg(0x33, 0x0e); // ENDPIXEL: set during sensor setup
+
+ dev->reg.init_reg(0x34, 0x40); // DUMMY: SENSOR_DEF
+ dev->reg.init_reg(0x35, 0x00); // MAXWD: set during scan setup
+ dev->reg.init_reg(0x36, 0x2a); // MAXWD: set during scan setup
+ dev->reg.init_reg(0x37, 0x30); // MAXWD: set during scan setup
+ dev->reg.init_reg(0x38, 0x2a); // LPERIOD: SENSOR_DEF
+ dev->reg.init_reg(0x39, 0xf8); // LPERIOD: SENSOR_DEF
+ dev->reg.init_reg(0x3d, 0x00); // FEEDL: set during motor setup
+ dev->reg.init_reg(0x3e, 0x00); // FEEDL: set during motor setup
+ dev->reg.init_reg(0x3f, 0x00); // FEEDL: set during motor setup
+
dev->reg.init_reg(0x52, 0x03); // SENSOR_DEF
dev->reg.init_reg(0x53, 0x07); // SENSOR_DEF
dev->reg.init_reg(0x54, 0x00); // SENSOR_DEF
@@ -177,30 +177,27 @@ gl847_init_registers (Genesys_Device * dev)
dev->reg.init_reg(0x58, 0x2a); // SENSOR_DEF
dev->reg.init_reg(0x59, 0xe1); // SENSOR_DEF
dev->reg.init_reg(0x5a, 0x55); // SENSOR_DEF
- dev->reg.init_reg(0x5e, 0x41);
- dev->reg.init_reg(0x5f, 0x40);
- dev->reg.init_reg(0x60, 0x00);
- dev->reg.init_reg(0x61, 0x21);
- dev->reg.init_reg(0x62, 0x40);
- dev->reg.init_reg(0x63, 0x00);
- dev->reg.init_reg(0x64, 0x21);
- dev->reg.init_reg(0x65, 0x40);
- dev->reg.init_reg(0x67, 0x80);
- dev->reg.init_reg(0x68, 0x80);
- dev->reg.init_reg(0x69, 0x20);
- dev->reg.init_reg(0x6a, 0x20);
-
- // CK1MAP
+
+ dev->reg.init_reg(0x5e, 0x41); // DECSEL, STOPTIM
+ dev->reg.init_reg(0x5f, 0x40); // FMOVDEC: set during motor setup
+
+ dev->reg.init_reg(0x60, 0x00); // Z1MOD: overwritten during motor setup
+ dev->reg.init_reg(0x61, 0x21); // Z1MOD: overwritten during motor setup
+ dev->reg.init_reg(0x62, 0x40); // Z1MOD: overwritten during motor setup
+ dev->reg.init_reg(0x63, 0x00); // Z2MOD: overwritten during motor setup
+ dev->reg.init_reg(0x64, 0x21); // Z2MOD: overwritten during motor setup
+ dev->reg.init_reg(0x65, 0x40); // Z2MOD: overwritten during motor setup
+ dev->reg.init_reg(0x67, 0x80); // STEPSEL, MTRPWM: overwritten during motor setup
+ dev->reg.init_reg(0x68, 0x80); // FSTPSEL, FASTPWM: overwritten during motor setup
+ dev->reg.init_reg(0x69, 0x20); // FSHDEC: overwritten during motor setup
+ dev->reg.init_reg(0x6a, 0x20); // FMOVNO: overwritten during motor setup
+
dev->reg.init_reg(0x74, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x75, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x76, 0x3c); // SENSOR_DEF
-
- // CK3MAP
dev->reg.init_reg(0x77, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x78, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x79, 0x9f); // SENSOR_DEF
-
- // CK4MAP
dev->reg.init_reg(0x7a, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x7b, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x7c, 0x55); // SENSOR_DEF
@@ -208,11 +205,23 @@ gl847_init_registers (Genesys_Device * dev)
dev->reg.init_reg(0x7d, 0x00);
// NOTE: autoconf is a non working option
- dev->reg.init_reg(0x87, 0x02);
- dev->reg.init_reg(0x9d, 0x06);
- dev->reg.init_reg(0xa2, 0x0f);
- dev->reg.init_reg(0xbd, 0x18);
- dev->reg.init_reg(0xfe, 0x08);
+ dev->reg.init_reg(0x87, 0x02); // TODO: move to SENSOR_DEF
+ dev->reg.init_reg(0x9d, 0x06); // RAMDLY, MOTLAG, CMODE, STEPTIM, IFRS
+ dev->reg.init_reg(0xa2, 0x0f); // misc
+
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ dev->reg.init_reg(0xab, 0x31);
+ dev->reg.init_reg(0xbb, 0x00);
+ dev->reg.init_reg(0xbc, 0x0f);
+ }
+ dev->reg.init_reg(0xbd, 0x18); // misc
+ dev->reg.init_reg(0xfe, 0x08); // misc
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ dev->reg.init_reg(0x9e, 0x00); // sensor reg, but not in SENSOR_DEF
+ dev->reg.init_reg(0x9f, 0x00); // sensor reg, but not in SENSOR_DEF
+ dev->reg.init_reg(0xaa, 0x00); // custom data
+ dev->reg.init_reg(0xff, 0x00);
+ }
// gamma[0] and gamma[256] values
dev->reg.init_reg(0xbe, 0x00);
@@ -237,233 +246,180 @@ gl847_init_registers (Genesys_Device * dev)
}
const auto& sensor = sanei_genesys_find_sensor_any(dev);
- sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res);
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, sensor.full_resolution,
+ 3, ScanMethod::FLATBED);
+ sanei_genesys_set_dpihw(dev->reg, dpihw_sensor.register_dpihw);
- /* initalize calibration reg */
- dev->calib_reg = dev->reg;
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ scanner_setup_sensor(*dev, sensor, dev->reg);
+ }
}
-/**@brief send slope table for motor movement
- * Send slope_table in machine byte order
- * @param dev device to send slope table
- * @param table_nr index of the slope table in ASIC memory
- * Must be in the [0-4] range.
- * @param slope_table pointer to 16 bit values array of the slope table
- * @param steps number of elements in the slope table
- */
-static void gl847_send_slope_table(Genesys_Device* dev, int table_nr,
- const std::vector<uint16_t>& slope_table,
- int steps)
+// Set values of analog frontend
+void CommandSetGl847::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const
{
- DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps);
- int i;
- char msg[10000];
-
- /* sanity check */
- if(table_nr<0 || table_nr>4)
- {
- throw SaneException("invalid table number %d", table_nr);
- }
-
- std::vector<uint8_t> table(steps * 2);
- for (i = 0; i < steps; i++)
- {
- table[i * 2] = slope_table[i] & 0xff;
- table[i * 2 + 1] = slope_table[i] >> 8;
- }
+ DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" :
+ set == AFE_SET ? "set" :
+ set == AFE_POWER_SAVE ? "powersave" : "huh?");
- if (DBG_LEVEL >= DBG_io)
- {
- std::sprintf(msg, "write slope %d (%d)=", table_nr, steps);
- for (i = 0; i < steps; i++)
- {
- std::sprintf(msg + std::strlen(msg), "%d", slope_table[i]);
- }
- DBG (DBG_io, "%s: %s\n", __func__, msg);
- }
+ (void) sensor;
- if (dev->interface->is_mock()) {
- dev->interface->record_slope_table(table_nr, slope_table);
+ if (dev->model->model_id != ModelId::CANON_5600F) {
+ // FIXME: remove the following read
+ dev->interface->read_register(REG_0x04);
}
- // slope table addresses are fixed
- dev->interface->write_ahb(0x10000000 + 0x4000 * table_nr, steps * 2, table.data());
-}
-
-/**
- * Set register values of Analog Device type frontend
- * */
-static void gl847_set_ad_fe(Genesys_Device* dev, uint8_t set)
-{
- DBG_HELPER(dbg);
- int i;
// wait for FE to be ready
auto status = scanner_read_status(*dev);
while (status.is_front_end_busy) {
dev->interface->sleep_ms(10);
status = scanner_read_status(*dev);
- };
-
- if (set == AFE_INIT)
- {
- DBG(DBG_proc, "%s(): setting DAC %u\n", __func__,
- static_cast<unsigned>(dev->model->adc_id));
-
- dev->frontend = dev->frontend_initial;
}
- // reset DAC
- dev->interface->write_fe_register(0x00, 0x80);
-
- // write them to analog frontend
- dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
-
- dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01));
+ if (set == AFE_INIT) {
+ dev->frontend = dev->frontend_initial;
+ }
- for (i = 0; i < 3; i++) {
- dev->interface->write_fe_register(0x02 + i, dev->frontend.get_gain(i));
+ if (dev->model->model_id != ModelId::CANON_5600F) {
+ // reset DAC (BUG: this does completely different thing on Analog Devices ADCs)
+ dev->interface->write_fe_register(0x00, 0x80);
+ } else {
+ if (dev->frontend.layout.type == FrontendType::WOLFSON) {
+ // reset DAC
+ dev->interface->write_fe_register(0x04, 0xff);
+ }
}
- for (i = 0; i < 3; i++) {
- dev->interface->write_fe_register(0x05 + i, dev->frontend.get_offset(i));
+
+ for (const auto& reg : dev->frontend.regs) {
+ dev->interface->write_fe_register(reg.address, reg.value);
}
}
-// Set values of analog frontend
-void CommandSetGl847::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const
+static void gl847_write_motor_phase_table(Genesys_Device& dev, unsigned ydpi)
{
- DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" :
- set == AFE_SET ? "set" :
- set == AFE_POWER_SAVE ? "powersave" : "huh?");
-
- (void) sensor;
-
- uint8_t val = dev->interface->read_register(REG_0x04);
- uint8_t frontend_type = val & REG_0x04_FESET;
-
- // route to AD devices
- if (frontend_type == 0x02) {
- gl847_set_ad_fe(dev, set);
- return;
+ (void) ydpi;
+ if (dev.model->model_id == ModelId::CANON_5600F) {
+ std::vector<std::uint8_t> phase_table = {
+ 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00,
+ 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00,
+ 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00,
+ 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00,
+ 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00,
+ 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00,
+ 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00,
+ 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x12, 0x00,
+ 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
+ 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,
+ 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00,
+ 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00,
+ 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00,
+ 0x28, 0x00, 0x28, 0x00, 0x28, 0x00, 0x28, 0x00,
+ 0x25, 0x00, 0x25, 0x00, 0x25, 0x00, 0x25, 0x00,
+ 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00,
+ };
+ dev.interface->write_ahb(0x01000a00, phase_table.size(), phase_table.data());
}
-
- throw SaneException("unsupported frontend type %d", frontend_type);
}
-
// @brief set up motor related register for scan
static void gl847_init_motor_regs_scan(Genesys_Device* dev,
const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
- const Motor_Profile& motor_profile,
+ const MotorProfile& motor_profile,
unsigned int scan_exposure_time,
unsigned scan_yres,
unsigned int scan_lines,
unsigned int scan_dummy,
unsigned int feed_steps,
- MotorFlag flags)
+ ScanFlag flags)
{
DBG_HELPER_ARGS(dbg, "scan_exposure_time=%d, can_yres=%d, step_type=%d, scan_lines=%d, "
"scan_dummy=%d, feed_steps=%d, flags=%x",
scan_exposure_time, scan_yres, static_cast<unsigned>(motor_profile.step_type),
scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
- int use_fast_fed;
- unsigned int fast_dpi;
- unsigned int feedl, dist;
- GenesysRegister *r;
- uint32_t z1, z2;
- unsigned int min_restep = 0x20;
- uint8_t val;
- unsigned int ccdlmt,tgtime;
unsigned step_multiplier = gl847_get_step_multiplier (reg);
- use_fast_fed=0;
- /* no fast fed since feed works well */
- if (dev->settings.yres==4444 && feed_steps > 100 && (!has_flag(flags, MotorFlag::FEED)))
- {
- use_fast_fed=1;
+ bool use_fast_fed = false;
+ if (dev->settings.yres == 4444 && feed_steps > 100 && !has_flag(flags, ScanFlag::FEEDING)) {
+ use_fast_fed = true;
+ }
+ if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
+ use_fast_fed = false;
}
- DBG(DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed);
reg->set24(REG_LINCNT, scan_lines);
- DBG(DBG_io, "%s: lincnt=%d\n", __func__, scan_lines);
- /* compute register 02 value */
- r = sanei_genesys_get_address(reg, REG_0x02);
- r->value = 0x00;
- sanei_genesys_set_motor_power(*reg, true);
+ reg->set8(REG_0x02, 0);
+ sanei_genesys_set_motor_power(*reg, true);
+ std::uint8_t reg02 = reg->get8(REG_0x02);
if (use_fast_fed) {
- r->value |= REG_0x02_FASTFED;
+ reg02 |= REG_0x02_FASTFED;
} else {
- r->value &= ~REG_0x02_FASTFED;
+ reg02 &= ~REG_0x02_FASTFED;
}
- if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) {
- r->value |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
+ if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
+ reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
}
- if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE)
- ||(scan_yres>=sensor.optical_res))
- {
- r->value |= REG_0x02_ACDCDIS;
+ if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) || (scan_yres >= sensor.full_resolution)) {
+ reg02 |= REG_0x02_ACDCDIS;
}
-
- if (has_flag(flags, MotorFlag::REVERSE)) {
- r->value |= REG_0x02_MTRREV;
+ if (has_flag(flags, ScanFlag::REVERSE)) {
+ reg02 |= REG_0x02_MTRREV;
} else {
- r->value &= ~REG_0x02_MTRREV;
+ reg02 &= ~REG_0x02_MTRREV;
}
+ reg->set8(REG_0x02, reg02);
- /* scan and backtracking slope table */
- auto scan_table = sanei_genesys_slope_table(dev->model->asic_type, scan_yres,
- scan_exposure_time, dev->motor.base_ydpi,
- step_multiplier, motor_profile);
- gl847_send_slope_table(dev, SCAN_TABLE, scan_table.table, scan_table.steps_count);
- gl847_send_slope_table(dev, BACKTRACK_TABLE, scan_table.table, scan_table.steps_count);
+ // scan and backtracking slope table
+ auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres,
+ scan_exposure_time, step_multiplier, motor_profile);
+ scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table);
+ scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table);
- /* fast table */
- fast_dpi=sanei_genesys_get_lowest_ydpi(dev);
+ // fast table
+ unsigned fast_dpi = sanei_genesys_get_lowest_ydpi(dev);
+
+ // BUG: looks like for fast moves we use inconsistent step type
StepType fast_step_type = motor_profile.step_type;
if (static_cast<unsigned>(motor_profile.step_type) >= static_cast<unsigned>(StepType::QUARTER)) {
fast_step_type = StepType::QUARTER;
}
- Motor_Profile fast_motor_profile = motor_profile;
+ MotorProfile fast_motor_profile = motor_profile;
fast_motor_profile.step_type = fast_step_type;
- auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_dpi,
- scan_exposure_time, dev->motor.base_ydpi,
- step_multiplier, fast_motor_profile);
+ auto fast_table = create_slope_table(dev->model->asic_type, dev->motor, fast_dpi,
+ scan_exposure_time, step_multiplier, fast_motor_profile);
+
+ scanner_send_slope_table(dev, sensor, STOP_TABLE, fast_table.table);
+ scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table);
+ scanner_send_slope_table(dev, sensor, HOME_TABLE, fast_table.table);
- gl847_send_slope_table(dev, STOP_TABLE, fast_table.table, fast_table.steps_count);
- gl847_send_slope_table(dev, FAST_TABLE, fast_table.table, fast_table.steps_count);
- gl847_send_slope_table(dev, HOME_TABLE, fast_table.table, fast_table.steps_count);
+ gl847_write_motor_phase_table(*dev, scan_yres);
- /* correct move distance by acceleration and deceleration amounts */
- feedl=feed_steps;
- if (use_fast_fed)
+ // correct move distance by acceleration and deceleration amounts
+ unsigned feedl = feed_steps;
+ unsigned dist = 0;
+ if (use_fast_fed)
{
feedl <<= static_cast<unsigned>(fast_step_type);
- dist = (scan_table.steps_count + 2 * fast_table.steps_count);
- /* TODO read and decode REG_0xAB */
- r = sanei_genesys_get_address (reg, 0x5e);
- dist += (r->value & 31);
- /* FEDCNT */
- r = sanei_genesys_get_address (reg, REG_FEDCNT);
- dist += r->value;
- }
- else
- {
+ dist = (scan_table.table.size() + 2 * fast_table.table.size());
+ // TODO read and decode REG_0xAB
+ dist += (reg->get8(0x5e) & 31);
+ dist += reg->get8(REG_FEDCNT);
+ } else {
feedl <<= static_cast<unsigned>(motor_profile.step_type);
- dist = scan_table.steps_count;
- if (has_flag(flags, MotorFlag::FEED)) {
+ dist = scan_table.table.size();
+ if (has_flag(flags, ScanFlag::FEEDING)) {
dist *= 2;
}
}
- DBG(DBG_io2, "%s: acceleration distance=%d\n", __func__, dist);
- /* check for overflow */
+ // check for overflow
if (dist < feedl) {
feedl -= dist;
} else {
@@ -471,25 +427,20 @@ static void gl847_init_motor_regs_scan(Genesys_Device* dev,
}
reg->set24(REG_FEEDL, feedl);
- DBG(DBG_io ,"%s: feedl=%d\n", __func__, feedl);
- r = sanei_genesys_get_address(reg, REG_0x0C);
- ccdlmt = (r->value & REG_0x0C_CCDLMT) + 1;
-
- r = sanei_genesys_get_address(reg, REG_0x1C);
- tgtime = 1<<(r->value & REG_0x1C_TGTIME);
+ unsigned ccdlmt = (reg->get8(REG_0x0C) & REG_0x0C_CCDLMT) + 1;
+ unsigned tgtime = 1 << (reg->get8(REG_0x1C) & REG_0x1C_TGTIME);
// hi res motor speed GPIO
uint8_t effective = dev->interface->read_register(REG_0x6C);
// if quarter step, bipolar Vref2
+ std::uint8_t val = effective;
if (motor_profile.step_type == StepType::QUARTER) {
val = effective & ~REG_0x6C_GPIO13;
} else if (static_cast<unsigned>(motor_profile.step_type) > static_cast<unsigned>(StepType::QUARTER)) {
val = effective | REG_0x6C_GPIO13;
- } else {
- val = effective;
}
dev->interface->write_register(REG_0x6C, val);
@@ -498,45 +449,37 @@ static void gl847_init_motor_regs_scan(Genesys_Device* dev,
val = effective | REG_0x6C_GPIO10;
dev->interface->write_register(REG_0x6C, val);
- min_restep = scan_table.steps_count / (2 * step_multiplier) - 1;
+ unsigned min_restep = scan_table.table.size() / (2 * step_multiplier) - 1;
if (min_restep < 1) {
min_restep = 1;
}
- r = sanei_genesys_get_address(reg, REG_FWDSTEP);
- r->value = min_restep;
- r = sanei_genesys_get_address(reg, REG_BWDSTEP);
- r->value = min_restep;
+ reg->set8(REG_FWDSTEP, min_restep);
+ reg->set8(REG_BWDSTEP, min_restep);
+
+ std::uint32_t z1, z2;
sanei_genesys_calculate_zmod(use_fast_fed,
- scan_exposure_time*ccdlmt*tgtime,
+ scan_exposure_time * ccdlmt * tgtime,
scan_table.table,
- scan_table.steps_count,
- feedl,
+ scan_table.table.size(),
+ feedl,
min_restep * step_multiplier,
&z1,
&z2);
- DBG(DBG_info, "%s: z1 = %d\n", __func__, z1);
reg->set24(REG_0x60, z1 | (static_cast<unsigned>(motor_profile.step_type) << (16+REG_0x60S_STEPSEL)));
-
- DBG(DBG_info, "%s: z2 = %d\n", __func__, z2);
reg->set24(REG_0x63, z2 | (static_cast<unsigned>(motor_profile.step_type) << (16+REG_0x63S_FSTPSEL)));
- r = sanei_genesys_get_address (reg, 0x1e);
- r->value &= 0xf0; /* 0 dummy lines */
- r->value |= scan_dummy; /* dummy lines */
+ reg->set8_mask(REG_0x1E, scan_dummy, 0x0f);
- r = sanei_genesys_get_address(reg, REG_0x67);
- r->value = REG_0x67_MTRPWM;
+ reg->set8(REG_0x67, REG_0x67_MTRPWM);
+ reg->set8(REG_0x68, REG_0x68_FASTPWM);
- r = sanei_genesys_get_address(reg, REG_0x68);
- r->value = REG_0x68_FASTPWM;
-
- reg->set8(REG_STEPNO, scan_table.steps_count / step_multiplier);
- reg->set8(REG_FASTNO, scan_table.steps_count / step_multiplier);
- reg->set8(REG_FSHDEC, scan_table.steps_count / step_multiplier);
- reg->set8(REG_FMOVNO, fast_table.steps_count / step_multiplier);
- reg->set8(REG_FMOVDEC, fast_table.steps_count / step_multiplier);
+ reg->set8(REG_STEPNO, scan_table.table.size() / step_multiplier);
+ reg->set8(REG_FASTNO, scan_table.table.size() / step_multiplier);
+ reg->set8(REG_FSHDEC, scan_table.table.size() / step_multiplier);
+ reg->set8(REG_FMOVNO, fast_table.table.size() / step_multiplier);
+ reg->set8(REG_FMOVDEC, fast_table.table.size() / step_multiplier);
}
@@ -563,84 +506,84 @@ static void gl847_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
const ScanSession& session)
{
DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time);
- unsigned dpihw;
- GenesysRegister *r;
-
- // resolution is divided according to ccd_pixels_per_system_pixel()
- unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel();
- DBG(DBG_io2, "%s: ccd_pixels_per_system_pixel=%d\n", __func__, ccd_pixels_per_system_pixel);
-
- // to manage high resolution device while keeping good low resolution scanning speed, we make
- // hardware dpi vary
- dpihw = sensor.get_register_hwdpi(session.params.xres * ccd_pixels_per_system_pixel);
- DBG(DBG_io2, "%s: dpihw=%d\n", __func__, dpihw);
- gl847_setup_sensor(dev, sensor, reg);
+ scanner_setup_sensor(*dev, sensor, *reg);
dev->cmd_set->set_fe(dev, sensor, AFE_SET);
/* enable shading */
regs_set_optical_off(dev->model->asic_type, *reg);
- r = sanei_genesys_get_address(reg, REG_0x01);
- r->value |= REG_0x01_SHDAREA;
+ reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA;
if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
- (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION))
+ has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) ||
+ session.use_host_side_calib)
{
- r->value &= ~REG_0x01_DVDSET;
- }
- else
- {
- r->value |= REG_0x01_DVDSET;
+ reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET;
+ } else {
+ reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET;
}
+ reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB;
- r = sanei_genesys_get_address (reg, REG_0x03);
- r->value &= ~REG_0x03_AVEENB;
-
+ reg->find_reg(REG_0x03).value &= ~REG_0x03_XPASEL;
+ if (has_flag(session.params.flags, ScanFlag::USE_XPA)) {
+ reg->find_reg(REG_0x03).value |= REG_0x03_XPASEL;
+ }
sanei_genesys_set_lamp_power(dev, sensor, *reg,
!has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
+ reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA);
+
+ if (has_flag(session.params.flags, ScanFlag::USE_XPA)) {
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ regs_set_exposure(dev->model->asic_type, *reg, sanei_genesys_fixup_exposure({0, 0, 0}));
+ }
+ }
- /* BW threshold */
- r = sanei_genesys_get_address (reg, 0x2e);
- r->value = dev->settings.threshold;
- r = sanei_genesys_get_address (reg, 0x2f);
- r->value = dev->settings.threshold;
+ // BW threshold
+ reg->set8(0x2e, 0x7f);
+ reg->set8(0x2f, 0x7f);
/* monochrome / color scan */
- r = sanei_genesys_get_address (reg, REG_0x04);
switch (session.params.depth) {
case 8:
- r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
+ reg->find_reg(REG_0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
break;
case 16:
- r->value &= ~REG_0x04_LINEART;
- r->value |= REG_0x04_BITSET;
+ reg->find_reg(REG_0x04).value &= ~REG_0x04_LINEART;
+ reg->find_reg(REG_0x04).value |= REG_0x04_BITSET;
break;
}
- r->value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
+ reg->find_reg(REG_0x04).value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
if (session.params.channels == 1)
{
switch (session.params.color_filter)
{
case ColorFilter::RED:
- r->value |= 0x14;
+ reg->find_reg(REG_0x04).value |= 0x14;
break;
case ColorFilter::BLUE:
- r->value |= 0x1c;
+ reg->find_reg(REG_0x04).value |= 0x1c;
break;
case ColorFilter::GREEN:
- r->value |= 0x18;
+ reg->find_reg(REG_0x04).value |= 0x18;
break;
default:
break; // should not happen
}
} else {
- r->value |= 0x10; // mono
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ reg->find_reg(REG_0x04).value |= 0x20;
+ } else {
+ reg->find_reg(REG_0x04).value |= 0x10; // mono
+ }
}
- sanei_genesys_set_dpihw(*reg, sensor, dpihw);
+ const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution,
+ session.params.channels,
+ session.params.scan_method);
+ sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw);
if (should_enable_gamma(session, sensor)) {
reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
@@ -651,38 +594,30 @@ static void gl847_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
/* CIS scanners can do true gray by setting LEDADD */
/* we set up LEDADD only when asked */
if (dev->model->is_cis) {
- r = sanei_genesys_get_address (reg, 0x87);
- r->value &= ~REG_0x87_LEDADD;
+ reg->find_reg(0x87).value &= ~REG_0x87_LEDADD;
+
if (session.enable_ledadd) {
- r->value |= REG_0x87_LEDADD;
+ reg->find_reg(0x87).value |= REG_0x87_LEDADD;
}
/* RGB weighting
- r = sanei_genesys_get_address (reg, 0x01);
- r->value &= ~REG_0x01_TRUEGRAY;
+ reg->find_reg(0x01).value &= ~REG_0x01_TRUEGRAY;
if (session.enable_ledadd) {
- r->value |= REG_0x01_TRUEGRAY;
+ reg->find_reg(0x01).value |= REG_0x01_TRUEGRAY;
}
*/
}
- unsigned dpiset = session.params.xres * ccd_pixels_per_system_pixel;
- reg->set16(REG_DPISET, dpiset);
- DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset);
-
+ reg->set16(REG_DPISET, sensor.register_dpiset);
reg->set16(REG_STRPIXEL, session.pixel_startx);
reg->set16(REG_ENDPIXEL, session.pixel_endx);
- build_image_pipeline(dev, session);
+ setup_image_pipeline(*dev, session);
/* MAXWD is expressed in 4 words unit */
// BUG: we shouldn't multiply by channels here
reg->set24(REG_MAXWD, (session.output_line_bytes_raw * session.params.channels >> 2));
-
reg->set16(REG_LPERIOD, exposure_time);
- DBG(DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time);
-
- r = sanei_genesys_get_address (reg, 0x34);
- r->value = sensor.dummy_pixel;
+ reg->set8(0x34, sensor.dummy_pixel);
}
void CommandSetGl847::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
@@ -692,13 +627,18 @@ void CommandSetGl847::init_regs_for_scan_session(Genesys_Device* dev, const Gene
DBG_HELPER(dbg);
session.assert_computed();
- int move;
int exposure_time;
int slope_dpi = 0;
int dummy = 0;
- dummy = 3 - session.params.channels;
+ if (dev->model->model_id == ModelId::CANON_LIDE_100 ||
+ dev->model->model_id == ModelId::CANON_LIDE_200 ||
+ dev->model->model_id == ModelId::CANON_LIDE_700F ||
+ dev->model->model_id == ModelId::HP_SCANJET_N6310)
+ {
+ dummy = 3 - session.params.channels;
+ }
/* slope_dpi */
/* cis color scan is effectively a gray scan with 3 gray lines per color
@@ -712,40 +652,15 @@ void CommandSetGl847::init_regs_for_scan_session(Genesys_Device* dev, const Gene
slope_dpi = slope_dpi * (1 + dummy);
exposure_time = sensor.exposure_lperiod;
- const auto& motor_profile = sanei_genesys_get_motor_profile(*gl847_motor_profiles,
- dev->model->motor_id,
- exposure_time);
-
- DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time);
- DBG(DBG_info, "%s : scan_step_type=%d\n", __func__,
- static_cast<unsigned>(motor_profile.step_type));
+ const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure_time, session);
/* we enable true gray for cis scanners only, and just when doing
* scan since color calibration is OK for this mode
*/
gl847_init_optical_regs_scan(dev, sensor, reg, exposure_time, session);
-
- move = session.params.starty;
- DBG(DBG_info, "%s: move=%d steps\n", __func__, move);
-
- MotorFlag mflags = MotorFlag::NONE;
- if (has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) {
- mflags |= MotorFlag::DISABLE_BUFFER_FULL_MOVE;
- }
- if (has_flag(session.params.flags, ScanFlag::FEEDING)) {
- mflags |= MotorFlag::FEED;
- }
- if (has_flag(session.params.flags, ScanFlag::REVERSE)) {
- mflags |= MotorFlag::REVERSE;
- }
-
gl847_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure_time, slope_dpi,
- dev->model->is_cis ? session.output_line_count * session.params.channels
- : session.output_line_count,
- dummy, move, mflags);
-
- dev->read_buffer.clear();
- dev->read_buffer.alloc(session.buffer_size_read);
+ session.optical_line_count, dummy, session.params.starty,
+ session.params.flags);
dev->read_active = true;
@@ -761,21 +676,59 @@ ScanSession CommandSetGl847::calculate_scan_session(const Genesys_Device* dev,
const Genesys_Sensor& sensor,
const Genesys_Settings& settings) const
{
- int start;
-
DBG(DBG_info, "%s ", __func__);
debug_dump(DBG_info, settings);
- /* start */
- start = static_cast<int>(dev->model->x_offset);
- start = static_cast<int>(start + settings.tl_x);
- start = static_cast<int>((start * sensor.optical_res) / MM_PER_INCH);
+ // backtracking isn't handled well, so don't enable it
+ ScanFlag flags = ScanFlag::DISABLE_BUFFER_FULL_MOVE;
+
+ /* Steps to move to reach scanning area:
+
+ - first we move to physical start of scanning either by a fixed steps amount from the
+ black strip or by a fixed amount from parking position, minus the steps done during
+ shading calibration.
+
+ - then we move by the needed offset whitin physical scanning area
+ */
+ unsigned move_dpi = dev->motor.base_ydpi;
+
+ float move = dev->model->y_offset;
+ if (settings.scan_method == ScanMethod::TRANSPARENCY ||
+ settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ // note: scanner_move_to_ta() function has already been called and the sensor is at the
+ // transparency adapter
+ if (!dev->ignore_offsets) {
+ move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta;
+ }
+ flags |= ScanFlag::USE_XPA;
+ } else {
+ if (!dev->ignore_offsets) {
+ move = dev->model->y_offset;
+ }
+ }
+
+ move = move + settings.tl_y;
+ move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
+ move -= dev->head_pos(ScanHeadId::PRIMARY);
+
+ float start = dev->model->x_offset;
+ if (settings.scan_method == ScanMethod::TRANSPARENCY ||
+ settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ start = dev->model->x_offset_ta;
+ } else {
+ start = dev->model->x_offset;
+ }
+
+ start = start + dev->settings.tl_x;
+ start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
ScanSession session;
session.params.xres = settings.xres;
session.params.yres = settings.yres;
- session.params.startx = start; // not used
- session.params.starty = 0; // not used
+ session.params.startx = static_cast<unsigned>(start);
+ session.params.starty = static_cast<unsigned>(move);
session.params.pixels = settings.pixels;
session.params.requested_pixels = settings.requested_pixels;
session.params.lines = settings.lines;
@@ -784,7 +737,7 @@ ScanSession CommandSetGl847::calculate_scan_session(const Genesys_Device* dev,
session.params.scan_method = settings.scan_method;
session.params.scan_mode = settings.scan_mode;
session.params.color_filter = settings.color_filter;
- session.params.flags = ScanFlag::NONE;
+ session.params.flags = flags;
compute_session(dev, session, sensor);
@@ -811,25 +764,61 @@ void CommandSetGl847::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens
DBG_HELPER(dbg);
(void) sensor;
uint8_t val;
- GenesysRegister *r;
- // clear GPIO 10
- if (dev->model->gpio_id != GpioId::CANON_LIDE_700F) {
+ if (reg->state.is_xpa_on && reg->state.is_lamp_on) {
+ dev->cmd_set->set_xpa_lamp_power(*dev, true);
+ }
+
+ if (dev->model->model_id == ModelId::HP_SCANJET_N6310 ||
+ dev->model->model_id == ModelId::CANON_LIDE_100 ||
+ dev->model->model_id == ModelId::CANON_LIDE_200)
+ {
val = dev->interface->read_register(REG_0x6C);
val &= ~REG_0x6C_GPIO10;
dev->interface->write_register(REG_0x6C, val);
}
- val = REG_0x0D_CLRLNCNT;
- dev->interface->write_register(REG_0x0D, val);
- val = REG_0x0D_CLRMCNT;
- dev->interface->write_register(REG_0x0D, val);
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ switch (dev->session.params.xres) {
+ case 75:
+ case 150:
+ case 300:
+ scanner_register_rw_bits(*dev, REG_0xA6, 0x04, 0x1c);
+ break;
+ case 600:
+ scanner_register_rw_bits(*dev, REG_0xA6, 0x18, 0x1c);
+ break;
+ case 1200:
+ scanner_register_rw_bits(*dev, REG_0xA6, 0x08, 0x1c);
+ break;
+ case 2400:
+ scanner_register_rw_bits(*dev, REG_0xA6, 0x10, 0x1c);
+ break;
+ case 4800:
+ scanner_register_rw_bits(*dev, REG_0xA6, 0x00, 0x1c);
+ break;
+ default:
+ throw SaneException("Unexpected xres");
+ }
+ dev->interface->write_register(0x6c, 0xf0);
+ dev->interface->write_register(0x6b, 0x87);
+ dev->interface->write_register(0x6d, 0x5f);
+ }
+
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ scanner_clear_scan_and_feed_counts(*dev);
+ } else {
+ // FIXME: use scanner_clear_scan_and_feed_counts()
+ val = REG_0x0D_CLRLNCNT;
+ dev->interface->write_register(REG_0x0D, val);
+ val = REG_0x0D_CLRMCNT;
+ dev->interface->write_register(REG_0x0D, val);
+ }
val = dev->interface->read_register(REG_0x01);
val |= REG_0x01_SCAN;
dev->interface->write_register(REG_0x01, val);
- r = sanei_genesys_get_address (reg, REG_0x01);
- r->value = val;
+ reg->set8(REG_0x01, val);
scanner_start_action(*dev, start_motor);
@@ -844,268 +833,86 @@ void CommandSetGl847::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg,
(void) reg;
DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop);
+ if (reg->state.is_xpa_on) {
+ dev->cmd_set->set_xpa_lamp_power(*dev, false);
+ }
+
if (!dev->model->is_sheetfed) {
scanner_stop_action(*dev);
}
}
-/** Park head
- * Moves the slider to the home (top) position slowly
- * @param dev device to park
- * @param wait_until_home true to make the function waiting for head
- * to be home before returning, if fals returne immediately
-*/
void CommandSetGl847::move_back_home(Genesys_Device* dev, bool wait_until_home) const
{
scanner_move_back_home(*dev, wait_until_home);
}
-// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi
-// from very top of scanner
-void CommandSetGl847::search_start_position(Genesys_Device* dev) const
-{
- DBG_HELPER(dbg);
- int size;
- Genesys_Register_Set local_reg;
-
- int pixels = 600;
- int dpi = 300;
-
- local_reg = dev->reg;
-
- /* sets for a 200 lines * 600 pixels */
- /* normal scan with no shading */
-
- // FIXME: the current approach of doing search only for one resolution does not work on scanners
- // whith employ different sensors with potentially different settings.
- const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method);
-
- ScanSession session;
- session.params.xres = dpi;
- session.params.yres = dpi;
- session.params.startx = 0;
- session.params.starty = 0; /*we should give a small offset here~60 steps */
- session.params.pixels = 600;
- session.params.lines = dev->model->search_lines;
- session.params.depth = 8;
- session.params.channels = 1;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::GRAY;
- session.params.color_filter = ColorFilter::GREEN;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &local_reg, session);
-
- // send to scanner
- dev->interface->write_registers(local_reg);
-
- size = pixels * dev->model->search_lines;
-
- std::vector<uint8_t> data(size);
-
- begin_scan(dev, sensor, &local_reg, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("search_start_position");
- end_scan(dev, &local_reg, true);
- dev->reg = local_reg;
- return;
- }
-
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- sanei_genesys_read_data_from_scanner(dev, data.data(), size);
-
- if (DBG_LEVEL >= DBG_data) {
- sanei_genesys_write_pnm_file("gl847_search_position.pnm", data.data(), 8, 1, pixels,
- dev->model->search_lines);
- }
-
- end_scan(dev, &local_reg, true);
-
- /* update regs to copy ASIC internal state */
- dev->reg = local_reg;
-
- // TODO: find out where sanei_genesys_search_reference_point stores information,
- // and use that correctly
- for (auto& sensor_update :
- sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method))
- {
- sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels,
- dev->model->search_lines);
- }
-}
-
-// sets up register for coarse gain calibration
-// todo: check it for scanners using it
-void CommandSetGl847::init_regs_for_coarse_calibration(Genesys_Device* dev,
- const Genesys_Sensor& sensor,
- Genesys_Register_Set& regs) const
-{
- DBG_HELPER(dbg);
-
- ScanSession session;
- session.params.xres = dev->settings.xres;
- session.params.yres = dev->settings.yres;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel();
- session.params.lines = 20;
- session.params.depth = 16;
- session.params.channels = dev->settings.get_channels();
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = dev->settings.scan_mode;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &regs, session);
-
- DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__,
- sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres);
-
- dev->interface->write_registers(regs);
-}
-
// init registers for shading calibration
void CommandSetGl847::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
DBG_HELPER(dbg);
- dev->calib_channels = 3;
+ unsigned move_dpi = dev->motor.base_ydpi;
- /* initial calibration reg values */
- regs = dev->reg;
+ float calib_size_mm = 0;
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ calib_size_mm = dev->model->y_size_calib_ta_mm;
+ } else {
+ calib_size_mm = dev->model->y_size_calib_mm;
+ }
- dev->calib_resolution = sensor.get_register_hwdpi(dev->settings.xres);
+ unsigned channels = 3;
+ unsigned resolution = sensor.shading_resolution;
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->calib_resolution,
- dev->calib_channels,
+ const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
- dev->calib_total_bytes_to_read = 0;
- dev->calib_lines = dev->model->shading_lines;
- if (dev->calib_resolution == 4800) {
- dev->calib_lines *= 2;
+ float move = 0;
+ ScanFlag flags = ScanFlag::DISABLE_SHADING |
+ ScanFlag::DISABLE_GAMMA |
+ ScanFlag::DISABLE_BUFFER_FULL_MOVE;
+
+ if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ // note: scanner_move_to_ta() function has already been called and the sensor is at the
+ // transparency adapter
+ move = dev->model->y_offset_calib_white_ta - dev->model->y_offset_sensor_to_ta;
+ flags |= ScanFlag::USE_XPA;
+ } else {
+ move = dev->model->y_offset_calib_white;
}
- dev->calib_pixels = (calib_sensor.sensor_pixels * dev->calib_resolution) /
- calib_sensor.optical_res;
- DBG(DBG_io, "%s: calib_lines = %zu\n", __func__, dev->calib_lines);
- DBG(DBG_io, "%s: calib_pixels = %zu\n", __func__, dev->calib_pixels);
+ move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
+
+ unsigned calib_lines = static_cast<unsigned>(calib_size_mm * resolution / MM_PER_INCH);
ScanSession session;
- session.params.xres = dev->calib_resolution;
- session.params.yres = dev->motor.base_ydpi;
+ session.params.xres = resolution;
+ session.params.yres = resolution;
session.params.startx = 0;
- session.params.starty = 20;
- session.params.pixels = dev->calib_pixels;
- session.params.lines = dev->calib_lines;
+ session.params.starty = static_cast<unsigned>(move);
+ session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
+ session.params.lines = calib_lines;
session.params.depth = 16;
- session.params.channels = dev->calib_channels;
+ session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::DISABLE_BUFFER_FULL_MOVE |
- ScanFlag::IGNORE_LINE_DISTANCE;
+ session.params.flags = flags;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
- dev->interface->write_registers(regs);
-
- /* we use GENESYS_FLAG_SHADING_REPARK */
+ /* we use ModelFlag::SHADING_REPARK */
dev->set_head_pos_zero(ScanHeadId::PRIMARY);
-}
-
-/** @brief set up registers for the actual scan
- */
-void CommandSetGl847::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const
-{
- DBG_HELPER(dbg);
- float move;
- int move_dpi;
- float start;
- debug_dump(DBG_info, dev->settings);
-
- /* steps to move to reach scanning area:
- - first we move to physical start of scanning
- either by a fixed steps amount from the black strip
- or by a fixed amount from parking position,
- minus the steps done during shading calibration
- - then we move by the needed offset whitin physical
- scanning area
-
- assumption: steps are expressed at maximum motor resolution
-
- we need:
- float y_offset;
- float y_size;
- float y_offset_calib;
- mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */
-
- /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is
- relative from origin, else, it is from parking position */
-
- move_dpi = dev->motor.base_ydpi;
-
- move = static_cast<float>(dev->model->y_offset);
- move = static_cast<float>(move + dev->settings.tl_y);
- move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
- move -= dev->head_pos(ScanHeadId::PRIMARY);
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
-
- /* fast move to scan area */
- /* we don't move fast the whole distance since it would involve
- * computing acceleration/deceleration distance for scan
- * resolution. So leave a remainder for it so scan makes the final
- * move tuning */
- if (dev->settings.get_channels() * dev->settings.yres >= 600 && move > 700) {
- scanner_move(*dev, dev->model->default_method, static_cast<unsigned>(move - 500),
- Direction::FORWARD);
- move=500;
- }
-
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
- DBG(DBG_info, "%s: move=%f steps\n", __func__, move);
-
- /* start */
- start = static_cast<float>(dev->model->x_offset);
- start = static_cast<float>(start + dev->settings.tl_x);
- start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH);
-
- ScanSession session;
- session.params.xres = dev->settings.xres;
- session.params.yres = dev->settings.yres;
- session.params.startx = static_cast<unsigned>(start);
- session.params.starty = static_cast<unsigned>(move);
- session.params.pixels = dev->settings.pixels;
- session.params.requested_pixels = dev->settings.requested_pixels;
- session.params.lines = dev->settings.lines;
- session.params.depth = dev->settings.depth;
- session.params.channels = dev->settings.get_channels();
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = dev->settings.scan_mode;
- session.params.color_filter = dev->settings.color_filter;
- // backtracking isn't handled well, so don't enable it
- session.params.flags = ScanFlag::DISABLE_BUFFER_FULL_MOVE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &dev->reg, session);
+ dev->calib_session = session;
}
-
/**
* Send shading calibration data. The buffer is considered to always hold values
* for all the channels.
@@ -1114,39 +921,24 @@ void CommandSetGl847::send_shading_data(Genesys_Device* dev, const Genesys_Senso
uint8_t* data, int size) const
{
DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size);
- uint32_t addr, length, i, x, factor, pixels;
- uint32_t dpiset, dpihw;
+ std::uint32_t addr, i;
uint8_t val,*ptr,*src;
- /* shading data is plit in 3 (up to 5 with IR) areas
- write(0x10014000,0x00000dd8)
- URB 23429 bulk_out len 3544 wrote 0x33 0x10 0x....
- write(0x1003e000,0x00000dd8)
- write(0x10068000,0x00000dd8)
- */
- length = static_cast<std::uint32_t>(size / 3);
- std::uint32_t strpixel = dev->session.pixel_startx;
- std::uint32_t endpixel = dev->session.pixel_endx;
+ unsigned length = static_cast<unsigned>(size / 3);
- /* compute deletion factor */
- dpiset = dev->reg.get16(REG_DPISET);
- dpihw = sensor.get_register_hwdpi(dpiset);
- factor=dpihw/dpiset;
- DBG(DBG_io2, "%s: factor=%d\n", __func__, factor);
+ // we're using SHDAREA, thus we only need to upload part of the line
+ unsigned offset = dev->session.pixel_count_ratio.apply(
+ dev->session.params.startx * sensor.full_resolution / dev->session.params.xres);
+ unsigned pixels = dev->session.pixel_count_ratio.apply(dev->session.optical_pixels_raw);
- pixels=endpixel-strpixel;
+ // turn pixel value into bytes 2x16 bits words
+ offset *= 2 * 2;
+ pixels *= 2 * 2;
- /* since we're using SHDAREA, substract startx coordinate from shading */
- strpixel -= (sensor.ccd_start_xoffset * 600) / sensor.optical_res;
-
- /* turn pixel value into bytes 2x16 bits words */
- strpixel*=2*2;
- pixels*=2*2;
-
- dev->interface->record_key_value("shading_offset", std::to_string(strpixel));
+ dev->interface->record_key_value("shading_offset", std::to_string(offset));
dev->interface->record_key_value("shading_pixels", std::to_string(pixels));
dev->interface->record_key_value("shading_length", std::to_string(length));
- dev->interface->record_key_value("shading_factor", std::to_string(factor));
+ dev->interface->record_key_value("shading_factor", std::to_string(sensor.shading_factor));
std::vector<uint8_t> buffer(pixels, 0);
@@ -1155,6 +947,10 @@ void CommandSetGl847::send_shading_data(Genesys_Device* dev, const Genesys_Senso
/* base addr of data has been written in reg D0-D4 in 4K word, so AHB address
* is 8192*reg value */
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ return;
+ }
+
/* write actual color channel data */
for(i=0;i<3;i++)
{
@@ -1162,11 +958,10 @@ void CommandSetGl847::send_shading_data(Genesys_Device* dev, const Genesys_Senso
* to the one corresponding to SHDAREA */
ptr = buffer.data();
- /* iterate on both sensor segment */
- for(x=0;x<pixels;x+=4*factor)
- {
+ // iterate on both sensor segment
+ for (unsigned x = 0; x < pixels; x += 4 * sensor.shading_factor) {
/* coefficient source */
- src=(data+strpixel+i*length)+x;
+ src = (data + offset + i * length) + x;
/* coefficient copy */
ptr[0]=src[0];
@@ -1192,160 +987,7 @@ void CommandSetGl847::send_shading_data(Genesys_Device* dev, const Genesys_Senso
SensorExposure CommandSetGl847::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
- DBG_HELPER(dbg);
- int num_pixels;
- int total_size;
- int used_res;
- int i, j;
- int val;
- int channels;
- int avg[3], top[3], bottom[3];
- int turn;
- uint16_t exp[3];
- float move;
-
- move = static_cast<float>(dev->model->y_offset_calib_white);
- move = static_cast<float>((move * (dev->motor.base_ydpi / 4)) / MM_PER_INCH);
- if (move > 20) {
- scanner_move(*dev, dev->model->default_method, static_cast<unsigned>(move),
- Direction::FORWARD);
- }
- DBG(DBG_io, "%s: move=%f steps\n", __func__, move);
-
- /* offset calibration is always done in color mode */
- channels = 3;
- used_res = sensor.get_register_hwdpi(dev->settings.xres);
- const auto& calib_sensor = sanei_genesys_find_sensor(dev, used_res, channels,
- dev->settings.scan_method);
- num_pixels = (calib_sensor.sensor_pixels * used_res) / calib_sensor.optical_res;
-
- /* initial calibration reg values */
- regs = dev->reg;
-
- ScanSession session;
- session.params.xres = used_res;
- session.params.yres = used_res;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = num_pixels;
- session.params.lines = 1;
- session.params.depth = 16;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, calib_sensor);
-
- init_regs_for_scan_session(dev, calib_sensor, &regs, session);
-
- total_size = num_pixels * channels * (session.params.depth/8) * 1;
- std::vector<uint8_t> line(total_size);
-
- // initial loop values and boundaries
- exp[0] = calib_sensor.exposure.red;
- exp[1] = calib_sensor.exposure.green;
- exp[2] = calib_sensor.exposure.blue;
-
- bottom[0] = 28000;
- bottom[1] = 28000;
- bottom[2] = 28000;
-
- top[0] = 32000;
- top[1] = 32000;
- top[2] = 32000;
-
- turn = 0;
-
- /* no move during led calibration */
- bool acceptable = false;
- sanei_genesys_set_motor_power(regs, false);
- do
- {
- // set up exposure
- regs.set16(REG_EXPR,exp[0]);
- regs.set16(REG_EXPG,exp[1]);
- regs.set16(REG_EXPB,exp[2]);
-
- // write registers and scan data
- dev->interface->write_registers(regs);
-
- DBG(DBG_info, "%s: starting line reading\n", __func__);
- begin_scan(dev, calib_sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("led_calibration");
- scanner_stop_action(*dev);
- move_back_home(dev, true);
- return calib_sensor.exposure;
- }
-
- sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
-
- // stop scanning
- scanner_stop_action(*dev);
-
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[30];
- std::snprintf(fn, 30, "gl847_led_%02d.pnm", turn);
- sanei_genesys_write_pnm_file(fn, line.data(), session.params.depth,
- channels, num_pixels, 1);
- }
-
- /* compute average */
- for (j = 0; j < channels; j++)
- {
- avg[j] = 0;
- for (i = 0; i < num_pixels; i++)
- {
- if (dev->model->is_cis)
- val =
- line[i * 2 + j * 2 * num_pixels + 1] * 256 +
- line[i * 2 + j * 2 * num_pixels];
- else
- val =
- line[i * 2 * channels + 2 * j + 1] * 256 +
- line[i * 2 * channels + 2 * j];
- avg[j] += val;
- }
-
- avg[j] /= num_pixels;
- }
-
- DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]);
-
- /* check if exposure gives average within the boundaries */
- acceptable = true;
- for(i=0;i<3;i++)
- {
- if (avg[i] < bottom[i] || avg[i] > top[i]) {
- auto target = (bottom[i] + top[i]) / 2;
- exp[i] = (exp[i] * target) / avg[i];
- acceptable = false;
- }
- }
-
- turn++;
- }
- while (!acceptable && turn < 100);
-
- DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]);
-
- // set these values as final ones for scan
- dev->reg.set16(REG_EXPR, exp[0]);
- dev->reg.set16(REG_EXPG, exp[1]);
- dev->reg.set16(REG_EXPB, exp[2]);
-
- // go back home
- if (move>20) {
- move_back_home(dev, true);
- }
-
- return { exp[0], exp[1], exp[2] };
+ return scanner_led_calibration(*dev, sensor, regs);
}
/**
@@ -1354,31 +996,37 @@ SensorExposure CommandSetGl847::led_calibration(Genesys_Device* dev, const Genes
static void gl847_init_gpio(Genesys_Device* dev)
{
DBG_HELPER(dbg);
- int idx=0;
- /* search GPIO profile */
- while(gpios[idx].gpio_id != GpioId::UNKNOWN && dev->model->gpio_id != gpios[idx].gpio_id) {
- idx++;
- }
- if (gpios[idx].gpio_id == GpioId::UNKNOWN) {
- throw SaneException("failed to find GPIO profile for sensor_id=%d",
- static_cast<unsigned>(dev->model->sensor_id));
- }
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ apply_registers_ordered(dev->gpo.regs, {0xa6, 0xa7, 0x6f, 0x6e},
+ [&](const GenesysRegisterSetting& reg)
+ {
+ dev->interface->write_register(reg.address, reg.value);
+ });
+ } else {
+ std::vector<std::uint16_t> order1 = { 0xa7, 0xa6, 0x6e };
+ std::vector<std::uint16_t> order2 = { 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0xa8, 0xa9 };
- dev->interface->write_register(REG_0xA7, gpios[idx].ra7);
- dev->interface->write_register(REG_0xA6, gpios[idx].ra6);
+ for (auto addr : order1) {
+ dev->interface->write_register(addr, dev->gpo.regs.find_reg(addr).value);
+ }
- dev->interface->write_register(REG_0x6E, gpios[idx].r6e);
- dev->interface->write_register(REG_0x6C, 0x00);
+ dev->interface->write_register(REG_0x6C, 0x00); // FIXME: Likely not needed
- dev->interface->write_register(REG_0x6B, gpios[idx].r6b);
- dev->interface->write_register(REG_0x6C, gpios[idx].r6c);
- dev->interface->write_register(REG_0x6D, gpios[idx].r6d);
- dev->interface->write_register(REG_0x6E, gpios[idx].r6e);
- dev->interface->write_register(REG_0x6F, gpios[idx].r6f);
+ for (auto addr : order2) {
+ dev->interface->write_register(addr, dev->gpo.regs.find_reg(addr).value);
+ }
- dev->interface->write_register(REG_0xA8, gpios[idx].ra8);
- dev->interface->write_register(REG_0xA9, gpios[idx].ra9);
+ for (const auto& reg : dev->gpo.regs) {
+ if (std::find(order1.begin(), order1.end(), reg.address) != order1.end()) {
+ continue;
+ }
+ if (std::find(order2.begin(), order2.end(), reg.address) != order2.end()) {
+ continue;
+ }
+ dev->interface->write_register(reg.address, reg.value);
+ }
+ }
}
/**
@@ -1387,77 +1035,24 @@ static void gl847_init_gpio(Genesys_Device* dev)
static void gl847_init_memory_layout(Genesys_Device* dev)
{
DBG_HELPER(dbg);
- int idx = 0;
- uint8_t val;
- /* point to per model memory layout */
- idx = 0;
- if (dev->model->model_id == ModelId::CANON_LIDE_100) {
- idx = 0;
- }
- if (dev->model->model_id == ModelId::CANON_LIDE_200) {
- idx = 1;
- }
- if (dev->model->model_id == ModelId::CANON_5600F) {
- idx = 2;
- }
- if (dev->model->model_id == ModelId::CANON_LIDE_700F) {
- idx = 3;
+ // FIXME: move to initial register list
+ switch (dev->model->model_id) {
+ case ModelId::CANON_LIDE_100:
+ case ModelId::CANON_LIDE_200:
+ dev->interface->write_register(REG_0x0B, 0x29);
+ break;
+ case ModelId::CANON_LIDE_700F:
+ dev->interface->write_register(REG_0x0B, 0x2a);
+ break;
+ default:
+ break;
}
- /* CLKSET nd DRAMSEL */
- val = layouts[idx].dramsel;
- dev->interface->write_register(REG_0x0B, val);
- dev->reg.find_reg(0x0b).value = val;
-
- /* prevent further writings by bulk write register */
- dev->reg.remove_reg(0x0b);
-
- /* setup base address for shading data. */
- /* values must be multiplied by 8192=0x4000 to give address on AHB */
- /* R-Channel shading bank0 address setting for CIS */
- dev->interface->write_register(0xd0, layouts[idx].rd0);
- /* G-Channel shading bank0 address setting for CIS */
- dev->interface->write_register(0xd1, layouts[idx].rd1);
- /* B-Channel shading bank0 address setting for CIS */
- dev->interface->write_register(0xd2, layouts[idx].rd2);
-
- /* setup base address for scanned data. */
- /* values must be multiplied by 1024*2=0x0800 to give address on AHB */
- /* R-Channel ODD image buffer 0x0124->0x92000 */
- /* size for each buffer is 0x16d*1k word */
- dev->interface->write_register(0xe0, layouts[idx].re0);
- dev->interface->write_register(0xe1, layouts[idx].re1);
- /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/
- dev->interface->write_register(0xe2, layouts[idx].re2);
- dev->interface->write_register(0xe3, layouts[idx].re3);
-
- /* R-Channel EVEN image buffer 0x0292 */
- dev->interface->write_register(0xe4, layouts[idx].re4);
- dev->interface->write_register(0xe5, layouts[idx].re5);
- /* R-Channel EVEN image buffer end-address 0x03ff*/
- dev->interface->write_register(0xe6, layouts[idx].re6);
- dev->interface->write_register(0xe7, layouts[idx].re7);
-
- /* same for green, since CIS, same addresses */
- dev->interface->write_register(0xe8, layouts[idx].re0);
- dev->interface->write_register(0xe9, layouts[idx].re1);
- dev->interface->write_register(0xea, layouts[idx].re2);
- dev->interface->write_register(0xeb, layouts[idx].re3);
- dev->interface->write_register(0xec, layouts[idx].re4);
- dev->interface->write_register(0xed, layouts[idx].re5);
- dev->interface->write_register(0xee, layouts[idx].re6);
- dev->interface->write_register(0xef, layouts[idx].re7);
-
-/* same for blue, since CIS, same addresses */
- dev->interface->write_register(0xf0, layouts[idx].re0);
- dev->interface->write_register(0xf1, layouts[idx].re1);
- dev->interface->write_register(0xf2, layouts[idx].re2);
- dev->interface->write_register(0xf3, layouts[idx].re3);
- dev->interface->write_register(0xf4, layouts[idx].re4);
- dev->interface->write_register(0xf5, layouts[idx].re5);
- dev->interface->write_register(0xf6, layouts[idx].re6);
- dev->interface->write_register(0xf7, layouts[idx].re7);
+ // prevent further writings by bulk write register
+ dev->reg.remove_reg(0x0b);
+
+ apply_reg_settings_to_device_write_only(*dev, dev->memory_layout.regs);
}
/* *
@@ -1486,15 +1081,17 @@ void CommandSetGl847::asic_boot(Genesys_Device* dev, bool cold) const
// Write initial registers
dev->interface->write_registers(dev->reg);
- /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */
- val = dev->reg.find_reg(0x0b).value & REG_0x0B_DRAMSEL;
- val = (val | REG_0x0B_ENBDRAM);
- dev->interface->write_register(REG_0x0B, val);
- dev->reg.find_reg(0x0b).value = val;
+ if (dev->model->model_id != ModelId::CANON_5600F) {
+ // Enable DRAM by setting a rising edge on bit 3 of reg 0x0b
+ // The initial register write also powers on SDRAM
+ val = dev->reg.find_reg(0x0b).value & REG_0x0B_DRAMSEL;
+ val = (val | REG_0x0B_ENBDRAM);
+ dev->interface->write_register(REG_0x0B, val);
+ dev->reg.find_reg(0x0b).value = val;
- /* CIS_LINE */
- dev->reg.init_reg(0x08, REG_0x08_CIS_LINE);
- dev->interface->write_register(0x08, dev->reg.find_reg(0x08).value);
+ // TODO: remove this write
+ dev->interface->write_register(0x08, dev->reg.find_reg(0x08).value);
+ }
// set up end access
dev->interface->write_0x8c(0x10, 0x0b);
@@ -1506,8 +1103,11 @@ void CommandSetGl847::asic_boot(Genesys_Device* dev, bool cold) const
// setup internal memory layout
gl847_init_memory_layout (dev);
- dev->reg.init_reg(0xf8, 0x01);
- dev->interface->write_register(0xf8, dev->reg.find_reg(0xf8).value);
+ if (dev->model->model_id != ModelId::CANON_5600F) {
+ // FIXME: move to memory layout
+ dev->reg.init_reg(0xf8, 0x01);
+ dev->interface->write_register(0xf8, dev->reg.find_reg(0xf8).value);
+ }
}
/**
@@ -1519,7 +1119,7 @@ void CommandSetGl847::init(Genesys_Device* dev) const
DBG_INIT ();
DBG_HELPER(dbg);
- sanei_genesys_asic_init(dev, 0);
+ sanei_genesys_asic_init(dev);
}
void CommandSetGl847::update_hardware_sensors(Genesys_Scanner* s) const
@@ -1566,517 +1166,16 @@ void CommandSetGl847::update_home_sensor_gpio(Genesys_Device& dev) const
}
}
-/** @brief 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 CommandSetGl847::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward,
- bool black) const
-{
- DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse");
- unsigned int pixels, lines, channels;
- Genesys_Register_Set local_reg;
- size_t size;
- unsigned int pass, count, found, x, y;
- char title[80];
-
- set_fe(dev, sensor, AFE_SET);
- scanner_stop_action(*dev);
-
- // set up for a gray scan at lowest dpi
- const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method);
- unsigned dpi = resolution_settings.get_min_resolution_x();
- channels = 1;
- /* 10 MM */
- /* lines = (10 * dpi) / MM_PER_INCH; */
- /* shading calibation is done with dev->motor.base_ydpi */
- lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi;
- pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res;
- dev->set_head_pos_zero(ScanHeadId::PRIMARY);
-
- local_reg = dev->reg;
-
- ScanSession session;
- session.params.xres = dpi;
- session.params.yres = dpi;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = pixels;
- session.params.lines = lines;
- session.params.depth = 8;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::GRAY;
- session.params.color_filter = ColorFilter::RED;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA;
- if (!forward) {
- session.params.flags |= ScanFlag::REVERSE;
- }
- compute_session(dev, session, sensor);
-
- size = pixels * channels * lines * (session.params.depth / 8);
- std::vector<uint8_t> data(size);
-
- init_regs_for_scan_session(dev, sensor, &local_reg, session);
-
- dev->interface->write_registers(local_reg);
-
- begin_scan(dev, sensor, &local_reg, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("search_strip");
- scanner_stop_action(*dev);
- return;
- }
-
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- sanei_genesys_read_data_from_scanner(dev, data.data(), size);
-
- scanner_stop_action(*dev);
-
- pass = 0;
- if (DBG_LEVEL >= DBG_data)
- {
- std::sprintf(title, "gl847_search_strip_%s_%s%02d.pnm",
- black ? "black" : "white", forward ? "fwd" : "bwd", pass);
- sanei_genesys_write_pnm_file(title, data.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- /* loop until strip is found or maximum pass number done */
- found = 0;
- while (pass < 20 && !found)
- {
- dev->interface->write_registers(local_reg);
-
- // now start scan
- begin_scan(dev, sensor, &local_reg, true);
-
- wait_until_buffer_non_empty(dev);
-
- // now we're on target, we can read data
- sanei_genesys_read_data_from_scanner(dev, data.data(), size);
-
- scanner_stop_action(*dev);
-
- if (DBG_LEVEL >= DBG_data)
- {
- std::sprintf(title, "gl847_search_strip_%s_%s%02d.pnm",
- black ? "black" : "white",
- forward ? "fwd" : "bwd", static_cast<int>(pass));
- sanei_genesys_write_pnm_file(title, data.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- /* search data to find black strip */
- /* when searching forward, we only need one line of the searched color since we
- * will scan forward. But when doing backward search, we need all the area of the
- * same color */
- if (forward)
- {
- for (y = 0; y < lines && !found; y++)
- {
- count = 0;
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < pixels; x++)
- {
- /* when searching for black, detect white pixels */
- if (black && data[y * pixels + x] > 90)
- {
- count++;
- }
- /* when searching for white, detect black pixels */
- if (!black && data[y * pixels + x] < 60)
- {
- count++;
- }
- }
-
- /* at end of line, if count >= 3%, line is not fully of the desired color
- * so we must go to next line of the buffer */
- /* count*100/pixels < 3 */
- if ((count * 100) / pixels < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__,
- pass, y);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
- (100 * count) / pixels);
- }
- }
- }
- else /* since calibration scans are done forward, we need the whole area
- to be of the required color when searching backward */
- {
- count = 0;
- for (y = 0; y < lines; y++)
- {
- /* count of white/black pixels depending on the color searched */
- for (x = 0; x < pixels; x++)
- {
- /* when searching for black, detect white pixels */
- if (black && data[y * pixels + x] > 90)
- {
- count++;
- }
- /* when searching for white, detect black pixels */
- if (!black && data[y * pixels + x] < 60)
- {
- count++;
- }
- }
- }
-
- /* at end of area, if count >= 3%, area is not fully of the desired color
- * so we must go to next buffer */
- if ((count * 100) / (pixels * lines) < 3)
- {
- found = 1;
- DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass);
- }
- else
- {
- DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count,
- (100 * count) / pixels);
- }
- }
- pass++;
- }
-
- if (found)
- {
- DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white");
- }
- else
- {
- throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white");
- }
-}
-
-/**
- * average dark pixels of a 8 bits scan
- */
-static int
-dark_average (uint8_t * data, unsigned int pixels, unsigned int lines,
- unsigned int channels, unsigned int black)
-{
- unsigned int i, j, k, average, count;
- unsigned int avg[3];
- uint8_t val;
-
- /* computes average value on black margin */
- for (k = 0; k < channels; k++)
- {
- avg[k] = 0;
- count = 0;
- for (i = 0; i < lines; i++)
- {
- for (j = 0; j < black; j++)
- {
- val = data[i * channels * pixels + j + k];
- avg[k] += val;
- count++;
- }
- }
- if (count)
- avg[k] /= count;
- DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]);
- }
- average = 0;
- for (i = 0; i < channels; i++)
- average += avg[i];
- average /= channels;
- DBG(DBG_info, "%s: average = %d\n", __func__, average);
- return average;
-}
-
void CommandSetGl847::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
- DBG_HELPER(dbg);
- unsigned channels;
- int pass = 0, avg, total_size;
- int topavg, bottomavg, lines;
- int top, bottom, black_pixels, pixels;
-
- // no gain nor offset for AKM AFE
- uint8_t reg04 = dev->interface->read_register(REG_0x04);
- if ((reg04 & REG_0x04_FESET) == 0x02) {
- return;
- }
-
- /* offset calibration is always done in color mode */
- channels = 3;
- dev->calib_pixels = sensor.sensor_pixels;
- lines=1;
- pixels= (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
- black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res;
- DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
-
- ScanSession session;
- session.params.xres = sensor.optical_res;
- session.params.yres = sensor.optical_res;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = pixels;
- session.params.lines = lines;
- session.params.depth = 8;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- init_regs_for_scan_session(dev, sensor, &regs, session);
-
- sanei_genesys_set_motor_power(regs, false);
-
- /* allocate memory for scans */
- total_size = pixels * channels * lines * (session.params.depth / 8); /* colors * bytes_per_color * scan lines */
-
- std::vector<uint8_t> first_line(total_size);
- std::vector<uint8_t> second_line(total_size);
-
- /* init gain */
- dev->frontend.set_gain(0, 0);
- dev->frontend.set_gain(1, 0);
- dev->frontend.set_gain(2, 0);
-
- /* scan with no move */
- bottom = 10;
- dev->frontend.set_offset(0, bottom);
- dev->frontend.set_offset(1, bottom);
- dev->frontend.set_offset(2, bottom);
-
- set_fe(dev, sensor, AFE_SET);
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting first line reading\n", __func__);
- begin_scan(dev, sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("offset_calibration");
- return;
- }
-
- sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size);
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[30];
- std::snprintf(fn, 30, "gl847_offset%03d.pnm", bottom);
- sanei_genesys_write_pnm_file(fn, first_line.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- bottomavg = dark_average (first_line.data(), pixels, lines, channels, black_pixels);
- DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg);
-
- /* now top value */
- top = 255;
- dev->frontend.set_offset(0, top);
- dev->frontend.set_offset(1, top);
- dev->frontend.set_offset(2, top);
- set_fe(dev, sensor, AFE_SET);
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting second line reading\n", __func__);
- begin_scan(dev, sensor, &regs, true);
- sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
-
- topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
- DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg);
-
- /* loop until acceptable level */
- while ((pass < 32) && (top - bottom > 1))
- {
- pass++;
-
- /* settings for new scan */
- dev->frontend.set_offset(0, (top + bottom) / 2);
- dev->frontend.set_offset(1, (top + bottom) / 2);
- dev->frontend.set_offset(2, (top + bottom) / 2);
-
- // scan with no move
- set_fe(dev, sensor, AFE_SET);
- dev->interface->write_registers(regs);
- DBG(DBG_info, "%s: starting second line reading\n", __func__);
- begin_scan(dev, sensor, &regs, true);
- sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size);
-
- if (DBG_LEVEL >= DBG_data)
- {
- char fn[30];
- std::snprintf(fn, 30, "gl847_offset%03d.pnm", dev->frontend.get_offset(1));
- sanei_genesys_write_pnm_file(fn, second_line.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels);
- DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1));
-
- /* compute new boundaries */
- if (topavg == avg)
- {
- topavg = avg;
- top = dev->frontend.get_offset(1);
- }
- else
- {
- bottomavg = avg;
- bottom = dev->frontend.get_offset(1);
- }
- }
- DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
- dev->frontend.get_offset(0),
- dev->frontend.get_offset(1),
- dev->frontend.get_offset(2));
+ scanner_offset_calibration(*dev, sensor, regs);
}
void CommandSetGl847::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const
{
- DBG_HELPER_ARGS(dbg, "dpi = %d", dpi);
- int pixels;
- int total_size;
- int i, j, channels;
- int max[3];
- float gain[3],coeff;
- int val, code, lines;
-
- // no gain nor offset for AKM AFE
- uint8_t reg04 = dev->interface->read_register(REG_0x04);
- if ((reg04 & REG_0x04_FESET) == 0x02) {
- return;
- }
-
- /* coarse gain calibration is always done in color mode */
- channels = 3;
-
- /* follow CKSEL */
- if(dev->settings.xres<sensor.optical_res)
- {
- coeff = 0.9f;
- }
- else
- {
- coeff=1.0;
- }
- lines=10;
- pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res;
-
- ScanSession session;
- session.params.xres = sensor.optical_res;
- session.params.yres = sensor.optical_res;
- session.params.startx = 0;
- session.params.starty = 0;
- session.params.pixels = pixels;
- session.params.lines = lines;
- session.params.depth = 8;
- session.params.channels = channels;
- session.params.scan_method = dev->settings.scan_method;
- session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
- session.params.color_filter = dev->settings.color_filter;
- session.params.flags = ScanFlag::DISABLE_SHADING |
- ScanFlag::DISABLE_GAMMA |
- ScanFlag::SINGLE_LINE |
- ScanFlag::IGNORE_LINE_DISTANCE;
- compute_session(dev, session, sensor);
-
- try {
- init_regs_for_scan_session(dev, sensor, &regs, session);
- } catch (...) {
- catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); });
- throw;
- }
-
- sanei_genesys_set_motor_power(regs, false);
-
- dev->interface->write_registers(regs);
-
- total_size = pixels * channels * (16 / session.params.depth) * lines;
-
- std::vector<uint8_t> line(total_size);
-
- set_fe(dev, sensor, AFE_SET);
- begin_scan(dev, sensor, &regs, true);
-
- if (is_testing_mode()) {
- dev->interface->test_checkpoint("coarse_gain_calibration");
- scanner_stop_action(*dev);
- move_back_home(dev, true);
- return;
- }
-
- sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
-
- if (DBG_LEVEL >= DBG_data) {
- sanei_genesys_write_pnm_file("gl847_gain.pnm", line.data(), session.params.depth,
- channels, pixels, lines);
- }
-
- /* average value on each channel */
- for (j = 0; j < channels; j++)
- {
- max[j] = 0;
- for (i = pixels/4; i < (pixels*3/4); i++)
- {
- if (dev->model->is_cis) {
- val = line[i + j * pixels];
- } else {
- val = line[i * channels + j];
- }
-
- max[j] += val;
- }
- max[j] = max[j] / (pixels/2);
-
- gain[j] = (static_cast<float>(sensor.gain_white_ref) * coeff) / max[j];
-
- /* turn logical gain value into gain code, checking for overflow */
- code = static_cast<int>(283 - 208 / gain[j]);
- if (code > 255)
- code = 255;
- else if (code < 0)
- code = 0;
- dev->frontend.set_gain(j, code);
-
- DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j],
- dev->frontend.get_gain(j));
- }
-
- if (dev->model->is_cis) {
- uint8_t gain0 = dev->frontend.get_gain(0);
- if (gain0 > dev->frontend.get_gain(1)) {
- gain0 = dev->frontend.get_gain(1);
- }
- if (gain0 > dev->frontend.get_gain(2)) {
- gain0 = dev->frontend.get_gain(2);
- }
- dev->frontend.set_gain(0, gain0);
- dev->frontend.set_gain(1, gain0);
- dev->frontend.set_gain(2, gain0);
- }
-
- if (channels == 1) {
- dev->frontend.set_gain(0, dev->frontend.get_gain(1));
- dev->frontend.set_gain(2, dev->frontend.get_gain(1));
- }
-
- scanner_stop_action(*dev);
-
- move_back_home(dev, true);
+ scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
}
bool CommandSetGl847::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
@@ -2086,14 +1185,11 @@ bool CommandSetGl847::needs_home_before_init_regs_for_scan(Genesys_Device* dev)
}
void CommandSetGl847::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs, int* channels,
- int* total_size) const
+ Genesys_Register_Set* regs) const
{
(void) dev;
(void) sensor;
(void) regs;
- (void) channels;
- (void) total_size;
throw SaneException("not implemented");
}
@@ -2125,16 +1221,5 @@ void CommandSetGl847::eject_document(Genesys_Device* dev) const
throw SaneException("not implemented");
}
-void CommandSetGl847::move_to_ta(Genesys_Device* dev) const
-{
- (void) dev;
- throw SaneException("not implemented");
-}
-
-std::unique_ptr<CommandSet> create_gl847_cmd_set()
-{
- return std::unique_ptr<CommandSet>(new CommandSetGl847{});
-}
-
} // namespace gl847
} // namespace genesys
diff --git a/backend/genesys/gl847.h b/backend/genesys/gl847.h
index a51c293..aa4fb85 100644
--- a/backend/genesys/gl847.h
+++ b/backend/genesys/gl847.h
@@ -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,17 +60,11 @@ public:
void init(Genesys_Device* dev) const override;
void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
- Genesys_Register_Set* regs, int* channels,
- int* total_size) const override;
-
- 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_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set* reg,
const ScanSession& session) const override;
@@ -149,8 +80,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;
@@ -166,8 +95,6 @@ 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;
@@ -176,11 +103,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,
int size) const override;
diff --git a/backend/genesys/gl847_registers.h b/backend/genesys/gl847_registers.h
index 0603a6a..aa3d43b 100644
--- a/backend/genesys/gl847_registers.h
+++ b/backend/genesys/gl847_registers.h
@@ -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;
diff --git a/backend/genesys/image.cpp b/backend/genesys/image.cpp
index 7d386c6..793a209 100644
--- a/backend/genesys/image.cpp
+++ b/backend/genesys/image.cpp
@@ -45,6 +45,10 @@
#include "image.h"
+#if defined(HAVE_TIFFIO_H)
+#include <tiffio.h>
+#endif
+
#include <array>
namespace genesys {
@@ -201,4 +205,68 @@ void convert_pixel_row_format(const std::uint8_t* in_data, PixelFormat in_format
}
}
+void write_tiff_file(const std::string& filename, const void* data, int depth, int channels,
+ int pixels_per_line, int lines)
+{
+ DBG_HELPER_ARGS(dbg, "depth=%d, channels=%d, ppl=%d, lines=%d", depth, channels,
+ pixels_per_line, lines);
+#if defined(HAVE_TIFFIO_H)
+ auto image = TIFFOpen(filename.c_str(), "w");
+ if (!image) {
+ dbg.log(DBG_error, "Could not save debug image");
+ return;
+ }
+ TIFFSetField(image, TIFFTAG_IMAGEWIDTH, pixels_per_line);
+ TIFFSetField(image, TIFFTAG_IMAGELENGTH, lines);
+ TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, depth);
+ TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, channels);
+ if (channels > 1) {
+ TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ } else {
+ TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ }
+ TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(image, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+
+ std::size_t bytes_per_line = (pixels_per_line * channels * depth + 7) / 8;
+ const std::uint8_t* data_ptr = reinterpret_cast<const std::uint8_t*>(data);
+
+ // we don't need to handle endian because libtiff will handle that
+ for (int iline = 0; iline < lines; ++iline) {
+ const auto* line_data = data_ptr + bytes_per_line * iline;
+ TIFFWriteScanline(image, const_cast<std::uint8_t*>(line_data), iline, 0);
+ }
+ TIFFClose(image);
+
+#else
+ dbg.log(DBG_error, "Backend has been built without TIFF library support. "
+ "Debug images will not be saved");
+#endif
+}
+
+bool is_supported_write_tiff_file_image_format(PixelFormat format)
+{
+ switch (format) {
+ case PixelFormat::I1:
+ case PixelFormat::RGB111:
+ case PixelFormat::I8:
+ case PixelFormat::RGB888:
+ case PixelFormat::I16:
+ case PixelFormat::RGB161616:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void write_tiff_file(const std::string& filename, const Image& image)
+{
+ if (!is_supported_write_tiff_file_image_format(image.get_format())) {
+ throw SaneException("Unsupported format %d", static_cast<unsigned>(image.get_format()));
+ }
+
+ write_tiff_file(filename, image.get_row_ptr(0), get_pixel_format_depth(image.get_format()),
+ get_pixel_channels(image.get_format()), image.get_width(), image.get_height());
+}
+
} // namespace genesys
diff --git a/backend/genesys/image.h b/backend/genesys/image.h
index c96b1bb..798594e 100644
--- a/backend/genesys/image.h
+++ b/backend/genesys/image.h
@@ -82,6 +82,11 @@ private:
void convert_pixel_row_format(const std::uint8_t* in_data, PixelFormat in_format,
std::uint8_t* out_data, PixelFormat out_format, std::size_t count);
+void write_tiff_file(const std::string& filename, const void* data, int depth,
+ int channels, int pixels_per_line, int lines);
+
+void write_tiff_file(const std::string& filename, const Image& image);
+
} // namespace genesys
#endif // ifndef BACKEND_GENESYS_IMAGE_H
diff --git a/backend/genesys/image_buffer.cpp b/backend/genesys/image_buffer.cpp
index 07c6987..c4f8019 100644
--- a/backend/genesys/image_buffer.cpp
+++ b/backend/genesys/image_buffer.cpp
@@ -45,13 +45,13 @@
#include "image_buffer.h"
#include "image.h"
+#include "utilities.h"
namespace genesys {
ImageBuffer::ImageBuffer(std::size_t size, ProducerCallback producer) :
producer_{producer},
- size_{size},
- buffer_offset_{size}
+ size_{size}
{
buffer_.resize(size_);
}
@@ -81,123 +81,30 @@ bool ImageBuffer::get_data(std::size_t size, std::uint8_t* out_data)
bool got_data = true;
do {
buffer_offset_ = 0;
- got_data &= producer_(size_, buffer_.data());
- copy_buffer();
- } while(out_data < out_data_end && got_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,
- ProducerCallback producer) :
- remaining_size_{total_size},
- buffer_model_{buffer_model},
- producer_{producer}
-{}
+ std::size_t size_to_read = size_;
+ if (remaining_size_ != BUFFER_SIZE_UNSET) {
+ size_to_read = std::min<std::uint64_t>(size_to_read, remaining_size_);
+ remaining_size_ -= size_to_read;
+ }
-bool ImageBufferGenesysUsb::get_data(std::size_t size, std::uint8_t* out_data)
-{
- const std::uint8_t* out_data_end = out_data + size;
+ std::size_t aligned_size_to_read = size_to_read;
+ if (remaining_size_ == 0 && last_read_multiple_ != BUFFER_SIZE_UNSET) {
+ aligned_size_to_read = align_multiple_ceil(size_to_read, last_read_multiple_);
+ }
- auto copy_buffer = [&]()
- {
- std::size_t bytes_copy = std::min<std::size_t>(out_data_end - out_data, available());
- std::memcpy(out_data, buffer_.data() + buffer_offset_, bytes_copy);
- out_data += bytes_copy;
- buffer_offset_ += bytes_copy;
- };
+ got_data &= producer_(aligned_size_to_read, buffer_.data());
+ curr_size_ = size_to_read;
- // first, read remaining data from buffer
- if (available() > 0) {
copy_buffer();
- }
-
- if (out_data == out_data_end) {
- return true;
- }
-
- // now the buffer is empty and there's more data to be read
- do {
- if (remaining_size_ == 0)
- return false;
- auto bytes_to_read = get_read_size();
- buffer_offset_ = 0;
- buffer_end_ = bytes_to_read;
- buffer_.resize(bytes_to_read);
-
- producer_(bytes_to_read, buffer_.data());
-
- if (remaining_size_ < bytes_to_read) {
- remaining_size_ = 0;
- } else {
- remaining_size_ -= bytes_to_read;
+ if (remaining_size_ == 0 && out_data < out_data_end) {
+ got_data = false;
}
- copy_buffer();
- } while(out_data < out_data_end);
- return true;
-}
-
-std::size_t ImageBufferGenesysUsb::get_read_size()
-{
- std::size_t size = buffer_model_.available_space();
+ } while (out_data < out_data_end && got_data);
- // never read an odd number. exception: last read
- // the chip internal counter does not count half words.
- size &= ~1;
-
- // Some setups need the reads to be multiples of 256 bytes
- size &= ~0xff;
-
- if (remaining_size_ < size) {
- size = remaining_size_;
- /*round up to a multiple of 256 bytes */
- size += (size & 0xff) ? 0x100 : 0x00;
- size &= ~0xff;
- }
-
- buffer_model_.simulate_read(size);
-
- return size;
+ return got_data;
}
} // namespace genesys
diff --git a/backend/genesys/image_buffer.h b/backend/genesys/image_buffer.h
index 43c3eb7..1910244 100644
--- a/backend/genesys/image_buffer.h
+++ b/backend/genesys/image_buffer.h
@@ -56,72 +56,33 @@ class ImageBuffer
{
public:
using ProducerCallback = std::function<bool(std::size_t size, std::uint8_t* out_data)>;
+ static constexpr std::uint64_t BUFFER_SIZE_UNSET = std::numeric_limits<std::uint64_t>::max();
ImageBuffer() {}
ImageBuffer(std::size_t size, ProducerCallback producer);
- std::size_t size() const { return size_; }
- std::size_t available() const { return size_ - buffer_offset_; }
+ std::size_t available() const { return curr_size_ - buffer_offset_; }
- bool get_data(std::size_t size, std::uint8_t* out_data);
-
-private:
- ProducerCallback producer_;
- std::size_t size_ = 0;
-
- std::size_t buffer_offset_ = 0;
- 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);
+ // allows adjusting the amount of data left so that we don't do a full size read from the
+ // producer on the last iteration. Set to BUFFER_SIZE_UNSET to ignore buffer size.
+ std::uint64_t remaining_size() const { return remaining_size_; }
+ void set_remaining_size(std::uint64_t bytes) { remaining_size_ = bytes; }
-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
-{
-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,
- ProducerCallback producer);
-
- std::size_t remaining_size() const { return remaining_size_; }
-
- void set_remaining_size(std::size_t bytes) { remaining_size_ = bytes; }
-
- std::size_t available() const { return buffer_end_ - buffer_offset_; }
+ // May be used to force the last read to be rounded up of a certain number of bytes
+ void set_last_read_multiple(std::uint64_t bytes) { last_read_multiple_ = bytes; }
bool get_data(std::size_t size, std::uint8_t* out_data);
private:
+ ProducerCallback producer_;
+ std::size_t size_ = 0;
+ std::size_t curr_size_ = 0;
- std::size_t get_read_size();
-
- std::size_t remaining_size_ = 0;
+ std::uint64_t remaining_size_ = BUFFER_SIZE_UNSET;
+ std::uint64_t last_read_multiple_ = BUFFER_SIZE_UNSET;
std::size_t buffer_offset_ = 0;
- std::size_t buffer_end_ = 0;
std::vector<std::uint8_t> buffer_;
-
- FakeBufferModel buffer_model_;
-
- ProducerCallback producer_;
};
} // namespace genesys
diff --git a/backend/genesys/image_pipeline.cpp b/backend/genesys/image_pipeline.cpp
index c01b7f4..8d67be9 100644
--- a/backend/genesys/image_pipeline.cpp
+++ b/backend/genesys/image_pipeline.cpp
@@ -53,15 +53,6 @@ namespace genesys {
ImagePipelineNode::~ImagePipelineNode() {}
-std::size_t ImagePipelineNodeBytesSource::consume_remaining_bytes(std::size_t bytes)
-{
- if (bytes > remaining_bytes_) {
- bytes = remaining_bytes_;
- }
- remaining_bytes_ -= bytes;
- return bytes;
-}
-
bool ImagePipelineNodeCallableSource::get_next_row_data(std::uint8_t* out_data)
{
bool got_data = producer_(get_row_bytes(), out_data);
@@ -78,7 +69,7 @@ ImagePipelineNodeBufferedCallableSource::ImagePipelineNodeBufferedCallableSource
format_{format},
buffer_{input_batch_size, producer}
{
- set_remaining_bytes(height_ * get_row_bytes());
+ buffer_.set_remaining_size(height_ * get_row_bytes());
}
bool ImagePipelineNodeBufferedCallableSource::get_next_row_data(std::uint8_t* out_data)
@@ -92,13 +83,7 @@ bool ImagePipelineNodeBufferedCallableSource::get_next_row_data(std::uint8_t* ou
bool got_data = true;
- auto row_bytes = get_row_bytes();
- auto bytes_to_ask = consume_remaining_bytes(row_bytes);
- if (bytes_to_ask < row_bytes) {
- got_data = false;
- }
-
- got_data &= buffer_.get_data(bytes_to_ask, out_data);
+ got_data &= buffer_.get_data(get_row_bytes(), out_data);
curr_row_++;
if (!got_data) {
eof_ = true;
@@ -106,37 +91,6 @@ bool ImagePipelineNodeBufferedCallableSource::get_next_row_data(std::uint8_t* ou
return got_data;
}
-
-ImagePipelineNodeBufferedGenesysUsb::ImagePipelineNodeBufferedGenesysUsb(
- std::size_t width, std::size_t height, PixelFormat format, std::size_t total_size,
- const FakeBufferModel& buffer_model, ProducerCallback producer) :
- width_{width},
- height_{height},
- format_{format},
- buffer_{total_size, buffer_model, producer}
-{
- set_remaining_bytes(total_size);
-}
-
-bool ImagePipelineNodeBufferedGenesysUsb::get_next_row_data(std::uint8_t* out_data)
-{
- if (remaining_bytes() != buffer_.remaining_size() + buffer_.available()) {
- buffer_.set_remaining_size(remaining_bytes() - buffer_.available());
- }
- bool got_data = true;
-
- std::size_t row_bytes = get_row_bytes();
- std::size_t ask_bytes = consume_remaining_bytes(row_bytes);
- if (ask_bytes < row_bytes) {
- got_data = false;
- }
- got_data &= buffer_.get_data(ask_bytes, out_data);
- if (!got_data) {
- eof_ = true;
- }
- return got_data;
-}
-
ImagePipelineNodeArraySource::ImagePipelineNodeArraySource(std::size_t width, std::size_t height,
PixelFormat format,
std::vector<std::uint8_t> data) :
@@ -151,7 +105,6 @@ ImagePipelineNodeArraySource::ImagePipelineNodeArraySource(std::size_t width, st
throw SaneException("The given array is too small (%zu bytes). Need at least %zu",
data_.size(), size);
}
- set_remaining_bytes(size);
}
bool ImagePipelineNodeArraySource::get_next_row_data(std::uint8_t* out_data)
@@ -161,21 +114,11 @@ bool ImagePipelineNodeArraySource::get_next_row_data(std::uint8_t* out_data)
return false;
}
- bool got_data = true;
-
auto row_bytes = get_row_bytes();
- auto bytes_to_ask = consume_remaining_bytes(row_bytes);
- if (bytes_to_ask < row_bytes) {
- got_data = false;
- }
-
- std::memcpy(out_data, data_.data() + get_row_bytes() * next_row_, bytes_to_ask);
+ std::memcpy(out_data, data_.data() + row_bytes * next_row_, row_bytes);
next_row_++;
- if (!got_data) {
- eof_ = true;
- }
- return got_data;
+ return true;
}
@@ -319,6 +262,50 @@ bool ImagePipelineNodeSwap16BitEndian::get_next_row_data(std::uint8_t* out_data)
return got_data;
}
+ImagePipelineNodeInvert::ImagePipelineNodeInvert(ImagePipelineNode& source) :
+ source_(source)
+{
+}
+
+bool ImagePipelineNodeInvert::get_next_row_data(std::uint8_t* out_data)
+{
+ bool got_data = source_.get_next_row_data(out_data);
+ auto num_values = get_width() * get_pixel_channels(source_.get_format());
+ auto depth = get_pixel_format_depth(source_.get_format());
+
+ switch (depth) {
+ case 16: {
+ auto* data = reinterpret_cast<std::uint16_t*>(out_data);
+ for (std::size_t i = 0; i < num_values; ++i) {
+ *data = 0xffff - *data;
+ data++;
+ }
+ break;
+ }
+ case 8: {
+ auto* data = out_data;
+ for (std::size_t i = 0; i < num_values; ++i) {
+ *data = 0xff - *data;
+ data++;
+ }
+ break;
+ }
+ case 1: {
+ auto* data = out_data;
+ auto num_bytes = (num_values + 7) / 8;
+ for (std::size_t i = 0; i < num_bytes; ++i) {
+ *data = ~*data;
+ data++;
+ }
+ break;
+ }
+ default:
+ throw SaneException("Unsupported pixel depth");
+ }
+
+ return got_data;
+}
+
ImagePipelineNodeMergeMonoLines::ImagePipelineNodeMergeMonoLines(ImagePipelineNode& source,
ColorOrder color_order) :
source_(source),
@@ -456,6 +443,12 @@ ImagePipelineNodeComponentShiftLines::ImagePipelineNodeComponentShiftLines(
static_cast<unsigned>(source.get_format()));
}
extra_height_ = *std::max_element(channel_shifts_.begin(), channel_shifts_.end());
+ height_ = source_.get_height();
+ if (extra_height_ > height_) {
+ height_ = 0;
+ } else {
+ height_ -= extra_height_;
+ }
}
bool ImagePipelineNodeComponentShiftLines::get_next_row_data(std::uint8_t* out_data)
@@ -492,18 +485,13 @@ ImagePipelineNodePixelShiftLines::ImagePipelineNodePixelShiftLines(
pixel_shifts_{shifts},
buffer_{get_row_bytes()}
{
- DBG_HELPER(dbg);
- DBG(DBG_proc, "%s: shifts={", __func__);
- for (auto el : pixel_shifts_) {
- DBG(DBG_proc, " %zu", el);
- }
- DBG(DBG_proc, " }\n");
-
- if (pixel_shifts_.size() > MAX_SHIFTS) {
- throw SaneException("Unsupported number of shift configurations %zu", pixel_shifts_.size());
- }
-
extra_height_ = *std::max_element(pixel_shifts_.begin(), pixel_shifts_.end());
+ height_ = source_.get_height();
+ if (extra_height_ > height_) {
+ height_ = 0;
+ } else {
+ height_ -= extra_height_;
+ }
}
bool ImagePipelineNodePixelShiftLines::get_next_row_data(std::uint8_t* out_data)
@@ -521,7 +509,8 @@ bool ImagePipelineNodePixelShiftLines::get_next_row_data(std::uint8_t* out_data)
auto format = get_format();
auto shift_count = pixel_shifts_.size();
- std::array<std::uint8_t*, MAX_SHIFTS> rows;
+ std::vector<std::uint8_t*> rows;
+ rows.resize(shift_count, nullptr);
for (std::size_t irow = 0; irow < shift_count; ++irow) {
rows[irow] = buffer_.get_row_ptr(pixel_shifts_[irow]);
@@ -536,6 +525,63 @@ bool ImagePipelineNodePixelShiftLines::get_next_row_data(std::uint8_t* out_data)
return got_data;
}
+ImagePipelineNodePixelShiftColumns::ImagePipelineNodePixelShiftColumns(
+ ImagePipelineNode& source, const std::vector<std::size_t>& shifts) :
+ source_(source),
+ pixel_shifts_{shifts}
+{
+ width_ = source_.get_width();
+ extra_width_ = compute_pixel_shift_extra_width(width_, pixel_shifts_);
+ if (extra_width_ > width_) {
+ width_ = 0;
+ } else {
+ width_ -= extra_width_;
+ }
+ temp_buffer_.resize(source_.get_row_bytes());
+}
+
+bool ImagePipelineNodePixelShiftColumns::get_next_row_data(std::uint8_t* out_data)
+{
+ if (width_ == 0) {
+ throw SaneException("Attempt to read zero-width line");
+ }
+ bool got_data = source_.get_next_row_data(temp_buffer_.data());
+
+ auto format = get_format();
+ auto shift_count = pixel_shifts_.size();
+
+ for (std::size_t x = 0, width = get_width(); x < width; x += shift_count) {
+ for (std::size_t ishift = 0; ishift < shift_count && x + ishift < width; ishift++) {
+ RawPixel pixel = get_raw_pixel_from_row(temp_buffer_.data(), x + pixel_shifts_[ishift],
+ format);
+ set_raw_pixel_to_row(out_data, x + ishift, pixel, format);
+ }
+ }
+ return got_data;
+}
+
+
+std::size_t compute_pixel_shift_extra_width(std::size_t source_width,
+ const std::vector<std::size_t>& shifts)
+{
+ // we iterate across pixel shifts and find the pixel that needs the maximum shift according to
+ // source_width.
+ int group_size = shifts.size();
+ int non_filled_group = source_width % shifts.size();
+ int extra_width = 0;
+
+ for (int i = 0; i < group_size; ++i) {
+ int shift_groups = shifts[i] / group_size;
+ int shift_rem = shifts[i] % group_size;
+
+ if (shift_rem < non_filled_group) {
+ shift_groups--;
+ }
+ extra_width = std::max(extra_width, shift_groups * group_size + non_filled_group - i);
+ }
+ return extra_width;
+}
+
ImagePipelineNodeExtract::ImagePipelineNodeExtract(ImagePipelineNode& source,
std::size_t offset_x, std::size_t offset_y,
std::size_t width, std::size_t height) :
@@ -666,16 +712,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]));
}
}
@@ -729,10 +780,8 @@ ImagePipelineNodeDebug::~ImagePipelineNodeDebug()
auto format = get_format();
buffer_.linearize();
- sanei_genesys_write_pnm_file(path_.c_str(), buffer_.get_front_row_ptr(),
- get_pixel_format_depth(format),
- get_pixel_channels(format),
- get_width(), buffer_.height());
+ write_tiff_file(path_, buffer_.get_front_row_ptr(), get_pixel_format_depth(format),
+ get_pixel_channels(format), get_width(), buffer_.height());
});
}
diff --git a/backend/genesys/image_pipeline.h b/backend/genesys/image_pipeline.h
index 2986837..d4aef49 100644
--- a/backend/genesys/image_pipeline.h
+++ b/backend/genesys/image_pipeline.h
@@ -75,18 +75,6 @@ public:
virtual bool get_next_row_data(std::uint8_t* out_data) = 0;
};
-class ImagePipelineNodeBytesSource : public ImagePipelineNode
-{
-public:
- std::size_t remaining_bytes() const { return remaining_bytes_; }
- void set_remaining_bytes(std::size_t bytes) { remaining_bytes_ = bytes; }
-
- std::size_t consume_remaining_bytes(std::size_t bytes);
-
-private:
- std::size_t remaining_bytes_ = 0;
-};
-
// A pipeline node that produces data from a callable
class ImagePipelineNodeCallableSource : public ImagePipelineNode
{
@@ -118,7 +106,7 @@ private:
};
// A pipeline node that produces data from a callable requesting fixed-size chunks.
-class ImagePipelineNodeBufferedCallableSource : public ImagePipelineNodeBytesSource
+class ImagePipelineNodeBufferedCallableSource : public ImagePipelineNode
{
public:
using ProducerCallback = std::function<bool(std::size_t size, std::uint8_t* out_data)>;
@@ -135,8 +123,9 @@ public:
bool get_next_row_data(std::uint8_t* out_data) override;
- std::size_t buffer_size() const { return buffer_.size(); }
- std::size_t buffer_available() const { return buffer_.available(); }
+ std::size_t remaining_bytes() const { return buffer_.remaining_size(); }
+ void set_remaining_bytes(std::size_t bytes) { buffer_.set_remaining_size(bytes); }
+ void set_last_read_multiple(std::size_t bytes) { buffer_.set_last_read_multiple(bytes); }
private:
ProducerCallback producer_;
@@ -150,39 +139,8 @@ private:
ImageBuffer buffer_;
};
-class ImagePipelineNodeBufferedGenesysUsb : public ImagePipelineNodeBytesSource
-{
-public:
- using ProducerCallback = std::function<void(std::size_t size, std::uint8_t* out_data)>;
-
- ImagePipelineNodeBufferedGenesysUsb(std::size_t width, std::size_t height,
- PixelFormat format, std::size_t total_size,
- const FakeBufferModel& buffer_model,
- ProducerCallback producer);
-
- std::size_t get_width() const override { return width_; }
- std::size_t get_height() const override { return height_; }
- PixelFormat get_format() const override { return format_; }
-
- bool eof() const override { return eof_; }
-
- bool get_next_row_data(std::uint8_t* out_data) override;
-
- std::size_t buffer_available() const { return buffer_.available(); }
-
-private:
- ProducerCallback producer_;
- std::size_t width_ = 0;
- std::size_t height_ = 0;
- PixelFormat format_ = PixelFormat::UNKNOWN;
-
- bool eof_ = false;
-
- ImageBufferGenesysUsb buffer_;
-};
-
// A pipeline node that produces data from the given array.
-class ImagePipelineNodeArraySource : public ImagePipelineNodeBytesSource
+class ImagePipelineNodeArraySource : public ImagePipelineNode
{
public:
ImagePipelineNodeArraySource(std::size_t width, std::size_t height, PixelFormat format,
@@ -302,7 +260,7 @@ public:
std::size_t pixels_per_chunk);
};
-// A pipeline that swaps bytes in 16-bit components on big-endian systems
+// A pipeline that swaps bytes in 16-bit components and does nothing otherwise.
class ImagePipelineNodeSwap16BitEndian : public ImagePipelineNode
{
public:
@@ -321,6 +279,23 @@ private:
bool needs_swapping_ = false;
};
+class ImagePipelineNodeInvert : public ImagePipelineNode
+{
+public:
+ ImagePipelineNodeInvert(ImagePipelineNode& source);
+
+ std::size_t get_width() const override { return source_.get_width(); }
+ std::size_t get_height() const override { return source_.get_height(); }
+ PixelFormat get_format() const override { return source_.get_format(); }
+
+ bool eof() const override { return source_.eof(); }
+
+ bool get_next_row_data(std::uint8_t* out_data) override;
+
+private:
+ ImagePipelineNode& source_;
+};
+
// A pipeline node that merges 3 mono lines into a color channel
class ImagePipelineNodeMergeMonoLines : public ImagePipelineNode
{
@@ -377,7 +352,7 @@ public:
unsigned shift_r, unsigned shift_g, unsigned shift_b);
std::size_t get_width() const override { return source_.get_width(); }
- std::size_t get_height() const override { return source_.get_height() - extra_height_; }
+ std::size_t get_height() const override { return height_; }
PixelFormat get_format() const override { return source_.get_format(); }
bool eof() const override { return source_.eof(); }
@@ -387,23 +362,23 @@ public:
private:
ImagePipelineNode& source_;
std::size_t extra_height_ = 0;
+ std::size_t height_ = 0;
std::array<unsigned, 3> channel_shifts_;
RowBuffer buffer_;
};
-// A pipeline node that shifts pixels across lines by the given offsets (performs unstaggering)
+// A pipeline node that shifts pixels across lines by the given offsets (performs vertical
+// unstaggering)
class ImagePipelineNodePixelShiftLines : public ImagePipelineNode
{
public:
- constexpr static std::size_t MAX_SHIFTS = 2;
-
ImagePipelineNodePixelShiftLines(ImagePipelineNode& source,
const std::vector<std::size_t>& shifts);
std::size_t get_width() const override { return source_.get_width(); }
- std::size_t get_height() const override { return source_.get_height() - extra_height_; }
+ std::size_t get_height() const override { return height_; }
PixelFormat get_format() const override { return source_.get_format(); }
bool eof() const override { return source_.eof(); }
@@ -413,12 +388,44 @@ public:
private:
ImagePipelineNode& source_;
std::size_t extra_height_ = 0;
+ std::size_t height_ = 0;
std::vector<std::size_t> pixel_shifts_;
RowBuffer buffer_;
};
+// A pipeline node that shifts pixels across columns by the given offsets. Each row is divided
+// into pixel groups of shifts.size() pixels. For each output group starting at position xgroup,
+// the i-th pixel will be set to the input pixel at position xgroup + shifts[i].
+class ImagePipelineNodePixelShiftColumns : public ImagePipelineNode
+{
+public:
+ ImagePipelineNodePixelShiftColumns(ImagePipelineNode& source,
+ const std::vector<std::size_t>& shifts);
+
+ std::size_t get_width() const override { return width_; }
+ std::size_t get_height() const override { return source_.get_height(); }
+ PixelFormat get_format() const override { return source_.get_format(); }
+
+ bool eof() const override { return source_.eof(); }
+
+ bool get_next_row_data(std::uint8_t* out_data) override;
+
+private:
+ ImagePipelineNode& source_;
+ std::size_t width_ = 0;
+ std::size_t extra_width_ = 0;
+
+ std::vector<std::size_t> pixel_shifts_;
+
+ std::vector<std::uint8_t> temp_buffer_;
+};
+
+// exposed for tests
+std::size_t compute_pixel_shift_extra_width(std::size_t source_width,
+ const std::vector<std::size_t>& shifts);
+
// A pipeline node that extracts a sub-image from the image. Padding and cropping is done as needed.
// The class can't pad to the left of the image currently, as only positive offsets are accepted.
class ImagePipelineNodeExtract : public ImagePipelineNode
@@ -476,7 +483,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(); }
@@ -517,6 +524,19 @@ class ImagePipelineStack
{
public:
ImagePipelineStack() {}
+ ImagePipelineStack(ImagePipelineStack&& other)
+ {
+ clear();
+ nodes_ = std::move(other.nodes_);
+ }
+
+ ImagePipelineStack& operator=(ImagePipelineStack&& other)
+ {
+ clear();
+ nodes_ = std::move(other.nodes_);
+ return *this;
+ }
+
~ImagePipelineStack() { clear(); }
std::size_t get_input_width() const;
@@ -536,20 +556,22 @@ public:
void clear();
template<class Node, class... Args>
- void push_first_node(Args&&... args)
+ Node& push_first_node(Args&&... args)
{
if (!nodes_.empty()) {
throw SaneException("Trying to append first node when there are existing nodes");
}
nodes_.emplace_back(std::unique_ptr<Node>(new Node(std::forward<Args>(args)...)));
+ return static_cast<Node&>(*nodes_.back());
}
template<class Node, class... Args>
- void push_node(Args&&... args)
+ Node& push_node(Args&&... args)
{
ensure_node_exists();
nodes_.emplace_back(std::unique_ptr<Node>(new Node(*nodes_.back(),
std::forward<Args>(args)...)));
+ return static_cast<Node&>(*nodes_.back());
}
bool get_next_row_data(std::uint8_t* out_data)
diff --git a/backend/genesys/image_pixel.h b/backend/genesys/image_pixel.h
index 2dda271..aa9980e 100644
--- a/backend/genesys/image_pixel.h
+++ b/backend/genesys/image_pixel.h
@@ -51,6 +51,7 @@
namespace genesys {
+// 16-bit values are in host endian
enum class PixelFormat
{
UNKNOWN,
diff --git a/backend/genesys/low.cpp b/backend/genesys/low.cpp
index 7937fcc..05ef46b 100644
--- a/backend/genesys/low.cpp
+++ b/backend/genesys/low.cpp
@@ -51,12 +51,23 @@
#include "gl124_registers.h"
#include "gl646_registers.h"
#include "gl841_registers.h"
+#include "gl842_registers.h"
#include "gl843_registers.h"
#include "gl846_registers.h"
#include "gl847_registers.h"
#include "gl646_registers.h"
+#include "gl124.h"
+#include "gl646.h"
+#include "gl841.h"
+#include "gl842.h"
+#include "gl843.h"
+#include "gl846.h"
+#include "gl847.h"
+#include "gl646.h"
+
#include <cstdio>
+#include <chrono>
#include <cmath>
#include <vector>
@@ -66,29 +77,17 @@
namespace genesys {
-/**
- * setup the hardware dependent functions
- */
-
-namespace gl124 { std::unique_ptr<CommandSet> create_gl124_cmd_set(); }
-namespace gl646 { std::unique_ptr<CommandSet> create_gl646_cmd_set(); }
-namespace gl841 { std::unique_ptr<CommandSet> create_gl841_cmd_set(); }
-namespace gl843 { std::unique_ptr<CommandSet> create_gl843_cmd_set(); }
-namespace gl846 { std::unique_ptr<CommandSet> create_gl846_cmd_set(); }
-namespace gl847 { std::unique_ptr<CommandSet> create_gl847_cmd_set(); }
-
-void sanei_genesys_init_cmd_set(Genesys_Device* dev)
+std::unique_ptr<CommandSet> create_cmd_set(AsicType asic_type)
{
- DBG_INIT ();
- DBG_HELPER(dbg);
- switch (dev->model->asic_type) {
- case AsicType::GL646: dev->cmd_set = gl646::create_gl646_cmd_set(); break;
- case AsicType::GL841: dev->cmd_set = gl841::create_gl841_cmd_set(); break;
- case AsicType::GL843: dev->cmd_set = gl843::create_gl843_cmd_set(); break;
+ switch (asic_type) {
+ case AsicType::GL646: return std::unique_ptr<CommandSet>(new gl646::CommandSetGl646{});
+ case AsicType::GL841: return std::unique_ptr<CommandSet>(new gl841::CommandSetGl841{});
+ case AsicType::GL842: return std::unique_ptr<CommandSet>(new gl842::CommandSetGl842{});
+ case AsicType::GL843: return std::unique_ptr<CommandSet>(new gl843::CommandSetGl843{});
case AsicType::GL845: // since only a few reg bits differs we handle both together
- case AsicType::GL846: dev->cmd_set = gl846::create_gl846_cmd_set(); break;
- case AsicType::GL847: dev->cmd_set = gl847::create_gl847_cmd_set(); break;
- case AsicType::GL124: dev->cmd_set = gl124::create_gl124_cmd_set(); break;
+ case AsicType::GL846: return std::unique_ptr<CommandSet>(new gl846::CommandSetGl846{});
+ case AsicType::GL847: return std::unique_ptr<CommandSet>(new gl847::CommandSetGl847{});
+ case AsicType::GL124: return std::unique_ptr<CommandSet>(new gl124::CommandSetGl124{});
default: throw SaneException(SANE_STATUS_INVAL, "unknown ASIC type");
}
}
@@ -108,116 +107,6 @@ void sanei_genesys_write_file(const char* filename, const std::uint8_t* data, st
std::fclose(out);
}
-// Write data to a pnm file (e.g. calibration). For debugging only
-// data is RGB or grey, with little endian byte order
-void sanei_genesys_write_pnm_file(const char* filename, const std::uint8_t* data, int depth,
- int channels, int pixels_per_line, int lines)
-{
- DBG_HELPER_ARGS(dbg, "depth=%d, channels=%d, ppl=%d, lines=%d", depth, channels,
- pixels_per_line, lines);
- int count;
-
- std::FILE* out = std::fopen(filename, "w");
- if (!out)
- {
- throw SaneException("could not open %s for writing: %s\n", filename, strerror(errno));
- }
- if(depth==1)
- {
- fprintf (out, "P4\n%d\n%d\n", pixels_per_line, lines);
- }
- else
- {
- std::fprintf(out, "P%c\n%d\n%d\n%d\n", channels == 1 ? '5' : '6', pixels_per_line, lines,
- static_cast<int>(std::pow(static_cast<double>(2),
- static_cast<double>(depth - 1))));
- }
- if (channels == 3)
- {
- for (count = 0; count < (pixels_per_line * lines * 3); count++)
- {
- if (depth == 16)
- fputc (*(data + 1), out);
- fputc (*(data++), out);
- if (depth == 16)
- data++;
- }
- }
- else
- {
- if (depth==1)
- {
- pixels_per_line/=8;
- }
- for (count = 0; count < (pixels_per_line * lines); count++)
- {
- switch (depth)
- {
- case 8:
- fputc (*(data + count), out);
- break;
- case 16:
- fputc (*(data + 1), out);
- fputc (*(data), out);
- data += 2;
- break;
- default:
- fputc(data[count], out);
- break;
- }
- }
- }
- std::fclose(out);
-}
-
-void sanei_genesys_write_pnm_file16(const char* filename, const uint16_t* data, unsigned channels,
- unsigned pixels_per_line, unsigned lines)
-{
- DBG_HELPER_ARGS(dbg, "channels=%d, ppl=%d, lines=%d", channels,
- pixels_per_line, lines);
-
- std::FILE* out = std::fopen(filename, "w");
- if (!out) {
- throw SaneException("could not open %s for writing: %s\n", filename, strerror(errno));
- }
- std::fprintf(out, "P%c\n%d\n%d\n%d\n", channels == 1 ? '5' : '6',
- pixels_per_line, lines, 256 * 256 - 1);
-
- for (unsigned count = 0; count < (pixels_per_line * lines * channels); count++) {
- fputc(*data >> 8, out);
- fputc(*data & 0xff, out);
- data++;
- }
- std::fclose(out);
-}
-
-bool is_supported_write_pnm_file_image_format(PixelFormat format)
-{
- switch (format) {
- case PixelFormat::I1:
- case PixelFormat::RGB111:
- case PixelFormat::I8:
- case PixelFormat::RGB888:
- case PixelFormat::I16:
- case PixelFormat::RGB161616:
- return true;
- default:
- return false;
- }
-}
-
-void sanei_genesys_write_pnm_file(const char* filename, const Image& image)
-{
- if (!is_supported_write_pnm_file_image_format(image.get_format())) {
- throw SaneException("Unsupported format %d", static_cast<unsigned>(image.get_format()));
- }
-
- sanei_genesys_write_pnm_file(filename, image.get_row_ptr(0),
- get_pixel_format_depth(image.get_format()),
- get_pixel_channels(image.get_format()),
- image.get_width(), image.get_height());
-}
-
/* ------------------------------------------------------------------------ */
/* Read and write RAM, registers and AFE */
/* ------------------------------------------------------------------------ */
@@ -276,6 +165,7 @@ Status scanner_read_status(Genesys_Device& dev)
case AsicType::GL124: address = 0x101; break;
case AsicType::GL646:
case AsicType::GL841:
+ case AsicType::GL842:
case AsicType::GL843:
case AsicType::GL845:
case AsicType::GL846:
@@ -336,28 +226,23 @@ void debug_print_status(DebugMessageHelper& dbg, Status val)
dbg.vlog(DBG_info, "status=%s\n", str.str().c_str());
}
-#if 0
-/* returns pixels per line from register set */
-/*candidate for moving into chip specific files?*/
-static int
-genesys_pixels_per_line (Genesys_Register_Set * reg)
+void scanner_register_rw_clear_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask)
{
- int pixels_per_line;
-
- pixels_per_line = reg->get8(0x32) * 256 + reg->get8(0x33);
- pixels_per_line -= (reg->get8(0x30) * 256 + reg->get8(0x31));
+ scanner_register_rw_bits(dev, address, 0x00, mask);
+}
- return pixels_per_line;
+void scanner_register_rw_set_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask)
+{
+ scanner_register_rw_bits(dev, address, mask, mask);
}
-/* returns dpiset from register set */
-/*candidate for moving into chip specific files?*/
-static int
-genesys_dpiset (Genesys_Register_Set * reg)
+void scanner_register_rw_bits(Genesys_Device& dev, std::uint16_t address,
+ std::uint8_t value, std::uint8_t mask)
{
- return reg->get8(0x2c) * 256 + reg->get8(0x2d);
+ auto reg_value = dev.interface->read_register(address);
+ reg_value = (reg_value & ~mask) | (value & mask);
+ dev.interface->write_register(address, reg_value);
}
-#endif
/** read the number of valid words in scanner's RAM
* ie registers 42-43-44
@@ -481,7 +366,7 @@ void wait_until_has_valid_words(Genesys_Device* dev)
unsigned words = 0;
unsigned sleep_time_ms = 10;
- for (unsigned wait_ms = 0; wait_ms < 50000; wait_ms += sleep_time_ms) {
+ for (unsigned wait_ms = 0; wait_ms < 70000; wait_ms += sleep_time_ms) {
sanei_genesys_read_valid_words(dev, &words);
if (words != 0)
break;
@@ -516,7 +401,7 @@ Image read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession&
dev->model->line_mode_color_order);
auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw);
- auto height = session.output_line_count * (dev->model->is_cis ? session.params.channels : 1);
+ auto height = session.optical_line_count;
Image image(width, height, format);
@@ -525,7 +410,7 @@ Image read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession&
throw SaneException("Trying to read too much data %zu (max %zu)", total_bytes, max_bytes);
}
if (total_bytes != max_bytes) {
- DBG(DBG_info, "WARNING %s: trying to read not enough data (%zu, full fill %zu\n", __func__,
+ DBG(DBG_info, "WARNING %s: trying to read not enough data (%zu, full fill %zu)\n", __func__,
total_bytes, max_bytes);
}
@@ -534,26 +419,138 @@ Image read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession&
ImagePipelineStack pipeline;
pipeline.push_first_node<ImagePipelineNodeImageSource>(image);
- if ((dev->model->flags & GENESYS_FLAG_16BIT_DATA_INVERTED) && session.params.depth == 16) {
- dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
+ if (session.segment_count > 1) {
+ auto output_width = session.output_segment_pixel_group_count * session.segment_count;
+ pipeline.push_node<ImagePipelineNodeDesegment>(output_width, dev->segment_order,
+ session.conseq_pixel_dist,
+ 1, 1);
}
+ if (session.params.depth == 16) {
+ unsigned num_swaps = 0;
+ if (has_flag(dev->model->flags, ModelFlag::SWAP_16BIT_DATA)) {
+ num_swaps++;
+ }
#ifdef WORDS_BIGENDIAN
- if (depth == 16) {
- dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
+ num_swaps++;
+#endif
+ if (num_swaps % 2 != 0) {
+ dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
+ }
}
+
+ if (has_flag(dev->model->flags, ModelFlag::INVERT_PIXEL_DATA)) {
+ pipeline.push_node<ImagePipelineNodeInvert>();
+ }
+
+ if (dev->model->is_cis && session.params.channels == 3) {
+ pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev->model->line_mode_color_order);
+ }
+
+ if (pipeline.get_output_format() == PixelFormat::BGR888) {
+ pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
+ }
+
+ if (pipeline.get_output_format() == PixelFormat::BGR161616) {
+ pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
+ }
+
+ return pipeline.get_image();
+}
+
+
+Image read_shuffled_image_from_scanner(Genesys_Device* dev, const ScanSession& session)
+{
+ DBG_HELPER(dbg);
+
+ std::size_t total_bytes = 0;
+ std::size_t pixels_per_line = 0;
+
+ if (dev->model->asic_type == AsicType::GL842 ||
+ dev->model->asic_type == AsicType::GL843 ||
+ dev->model->model_id == ModelId::CANON_5600F)
+ {
+ pixels_per_line = session.output_pixels;
+ } else {
+ // BUG: this selects incorrect pixel number
+ pixels_per_line = session.params.pixels;
+ }
+
+ // FIXME: the current calculation is likely incorrect on non-GL843 implementations,
+ // but this needs checking. Note the extra line when computing size.
+ if (dev->model->asic_type == AsicType::GL842 ||
+ dev->model->asic_type == AsicType::GL843 ||
+ dev->model->model_id == ModelId::CANON_5600F)
+ {
+ total_bytes = session.output_total_bytes_raw;
+ } else {
+ total_bytes = session.params.channels * 2 * pixels_per_line * (session.params.lines + 1);
+ }
+
+ auto format = create_pixel_format(session.params.depth,
+ dev->model->is_cis ? 1 : session.params.channels,
+ dev->model->line_mode_color_order);
+
+ // auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw);
+ auto width = pixels_per_line;
+ auto height = session.params.lines + 1; // BUG: incorrect
+ if (dev->model->asic_type == AsicType::GL842 ||
+ dev->model->asic_type == AsicType::GL843 ||
+ dev->model->model_id == ModelId::CANON_5600F)
+ {
+ height = session.optical_line_count;
+ }
+
+ Image image(width, height, format);
+
+ auto max_bytes = image.get_row_bytes() * height;
+ if (total_bytes > max_bytes) {
+ throw SaneException("Trying to read too much data %zu (max %zu)", total_bytes, max_bytes);
+ }
+ if (total_bytes != max_bytes) {
+ DBG(DBG_info, "WARNING %s: trying to read not enough data (%zu, full fill %zu)\n", __func__,
+ total_bytes, max_bytes);
+ }
+
+ sanei_genesys_read_data_from_scanner(dev, image.get_row_ptr(0), total_bytes);
+
+ ImagePipelineStack pipeline;
+ pipeline.push_first_node<ImagePipelineNodeImageSource>(image);
+
+ if (session.segment_count > 1) {
+ auto output_width = session.output_segment_pixel_group_count * session.segment_count;
+ pipeline.push_node<ImagePipelineNodeDesegment>(output_width, dev->segment_order,
+ session.conseq_pixel_dist,
+ 1, 1);
+ }
+
+ if (session.params.depth == 16) {
+ unsigned num_swaps = 0;
+ if (has_flag(dev->model->flags, ModelFlag::SWAP_16BIT_DATA)) {
+ num_swaps++;
+ }
+#ifdef WORDS_BIGENDIAN
+ num_swaps++;
#endif
+ if (num_swaps % 2 != 0) {
+ dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
+ }
+ }
+
+ if (has_flag(dev->model->flags, ModelFlag::INVERT_PIXEL_DATA)) {
+ pipeline.push_node<ImagePipelineNodeInvert>();
+ }
if (dev->model->is_cis && session.params.channels == 3) {
- dev->pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev->model->line_mode_color_order);
+ pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev->model->line_mode_color_order);
}
- if (dev->pipeline.get_output_format() == PixelFormat::BGR888) {
- dev->pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
+ if (pipeline.get_output_format() == PixelFormat::BGR888) {
+ pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
}
- if (dev->pipeline.get_output_format() == PixelFormat::BGR161616) {
- dev->pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
+ if (pipeline.get_output_format() == PixelFormat::BGR161616) {
+ pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
}
return pipeline.get_image();
@@ -600,34 +597,27 @@ void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sen
if (dev->model->asic_type == AsicType::GL843) {
regs_set_exposure(dev->model->asic_type, regs, sensor.exposure);
+ }
- // we don't actually turn on lamp on infrared scan
- if ((dev->model->model_id == ModelId::CANON_8400F ||
- dev->model->model_id == ModelId::CANON_8600F ||
- dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
- dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) &&
- dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
- {
- regs.find_reg(0x03).value &= ~REG_0x03_LAMPPWR;
- }
+ // we don't actually turn on lamp on infrared scan
+ if ((dev->model->model_id == ModelId::CANON_8400F ||
+ dev->model->model_id == ModelId::CANON_8600F ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I) &&
+ dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
+ {
+ regs.find_reg(0x03).value &= ~REG_0x03_LAMPPWR;
}
} else {
regs.find_reg(0x03).value &= ~REG_0x03_LAMPPWR;
if (dev->model->asic_type == AsicType::GL841) {
- regs_set_exposure(dev->model->asic_type, regs, {0x0101, 0x0101, 0x0101});
+ regs_set_exposure(dev->model->asic_type, regs, sanei_genesys_fixup_exposure({0, 0, 0}));
regs.set8(0x19, 0xff);
}
-
- if (dev->model->asic_type == AsicType::GL843) {
- if (dev->model->model_id == ModelId::PANASONIC_KV_SS080 ||
- dev->model->model_id == ModelId::HP_SCANJET_4850C ||
- dev->model->model_id == ModelId::HP_SCANJET_G4010 ||
- dev->model->model_id == ModelId::HP_SCANJET_G4050)
- {
- // BUG: datasheet says we shouldn't set exposure to zero
- regs_set_exposure(dev->model->asic_type, regs, {0, 0, 0});
- }
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ regs_set_exposure(dev->model->asic_type, regs, sanei_genesys_fixup_exposure({0, 0, 0}));
}
}
regs.state.is_lamp_on = set;
@@ -786,218 +776,144 @@ void sanei_genesys_send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& s
}
}
-static unsigned align_int_up(unsigned num, unsigned alignment)
-{
- unsigned mask = alignment - 1;
- if (num & mask)
- num = (num & ~mask) + alignment;
- return num;
-}
-
-void compute_session_buffer_sizes(AsicType asic, ScanSession& s)
+void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s,
+ const Genesys_Sensor& sensor)
{
- size_t line_bytes = s.output_line_bytes;
- size_t line_bytes_stagger = s.output_line_bytes;
-
- if (asic != AsicType::GL646) {
- // BUG: this is historical artifact and should be removed. Note that buffer sizes affect
- // how often we request the scanner for data and thus change the USB traffic.
- line_bytes_stagger =
- multiply_by_depth_ceil(s.optical_pixels, s.params.depth) * s.params.channels;
- }
-
- struct BufferConfig {
- size_t* result_size = nullptr;
- size_t lines = 0;
- size_t lines_mult = 0;
- size_t max_size = 0; // does not apply if 0
- size_t stagger_lines = 0;
-
- BufferConfig() = default;
- BufferConfig(std::size_t* rs, std::size_t l, std::size_t lm, std::size_t ms,
- std::size_t sl) :
- result_size{rs},
- lines{l},
- lines_mult{lm},
- max_size{ms},
- stagger_lines{sl}
- {}
- };
+ if (dev->model->asic_type == AsicType::GL646) {
+ s.pixel_startx += s.output_startx * sensor.full_resolution / s.params.xres;
+ s.pixel_endx = s.pixel_startx + s.optical_pixels * s.full_resolution / s.optical_resolution;
- std::array<BufferConfig, 4> configs;
- if (asic == AsicType::GL124 || asic == AsicType::GL843) {
- configs = { {
- { &s.buffer_size_read, 32, 1, 0, s.max_color_shift_lines + s.num_staggered_lines },
- { &s.buffer_size_lines, 32, 1, 0, s.max_color_shift_lines + s.num_staggered_lines },
- { &s.buffer_size_shrink, 16, 1, 0, 0 },
- { &s.buffer_size_out, 8, 1, 0, 0 },
- } };
- } else if (asic == AsicType::GL841) {
- size_t max_buf = sanei_genesys_get_bulk_max_size(asic);
- configs = { {
- { &s.buffer_size_read, 8, 2, max_buf, s.max_color_shift_lines + s.num_staggered_lines },
- { &s.buffer_size_lines, 8, 2, max_buf, s.max_color_shift_lines + s.num_staggered_lines },
- { &s.buffer_size_shrink, 8, 1, max_buf, 0 },
- { &s.buffer_size_out, 8, 1, 0, 0 },
- } };
- } else {
- configs = { {
- { &s.buffer_size_read, 16, 1, 0, s.max_color_shift_lines + s.num_staggered_lines },
- { &s.buffer_size_lines, 16, 1, 0, s.max_color_shift_lines + s.num_staggered_lines },
- { &s.buffer_size_shrink, 8, 1, 0, 0 },
- { &s.buffer_size_out, 8, 1, 0, 0 },
- } };
- }
-
- for (BufferConfig& config : configs) {
- size_t buf_size = line_bytes * config.lines;
- if (config.max_size > 0 && buf_size > config.max_size) {
- buf_size = (config.max_size / line_bytes) * line_bytes;
+ } else 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 ||
+ dev->model->asic_type == AsicType::GL847)
+ {
+ unsigned startx_xres = s.optical_resolution;
+ if (dev->model->model_id == ModelId::CANON_5600F ||
+ dev->model->model_id == ModelId::CANON_LIDE_90)
+ {
+ if (s.output_resolution == 1200) {
+ startx_xres /= 2;
+ }
+ if (s.output_resolution >= 2400) {
+ startx_xres /= 4;
+ }
}
- buf_size *= config.lines_mult;
- buf_size += line_bytes_stagger * config.stagger_lines;
- *config.result_size = buf_size;
- }
-}
-
-void compute_session_pipeline(const Genesys_Device* dev, ScanSession& s)
-{
- auto channels = s.params.channels;
- auto depth = s.params.depth;
+ s.pixel_startx = (s.output_startx * startx_xres) / s.params.xres;
+ s.pixel_endx = s.pixel_startx + s.optical_pixels_raw;
- s.pipeline_needs_reorder = true;
- if (channels != 3 && depth != 16) {
- s.pipeline_needs_reorder = false;
- }
-#ifndef WORDS_BIGENDIAN
- if (channels != 3 && depth == 16) {
- s.pipeline_needs_reorder = false;
- }
- if (channels == 3 && depth == 16 && !dev->model->is_cis &&
- dev->model->line_mode_color_order == ColorOrder::RGB)
+ } else if (dev->model->asic_type == AsicType::GL124)
{
- s.pipeline_needs_reorder = false;
+ s.pixel_startx = s.output_startx * sensor.full_resolution / s.params.xres;
+ s.pixel_endx = s.pixel_startx + s.optical_pixels_raw;
}
-#endif
- if (channels == 3 && depth == 8 && !dev->model->is_cis &&
- dev->model->line_mode_color_order == ColorOrder::RGB)
+
+ // align pixels to correct boundary for unstaggering
+ unsigned needed_x_alignment = std::max(s.stagger_x.size(), s.stagger_y.size());
+ unsigned aligned_pixel_startx = align_multiple_floor(s.pixel_startx, needed_x_alignment);
+ s.pixel_endx -= s.pixel_startx - aligned_pixel_startx;
+ s.pixel_startx = aligned_pixel_startx;
+
+ s.pixel_startx = sensor.pixel_count_ratio.apply(s.pixel_startx);
+ s.pixel_endx = sensor.pixel_count_ratio.apply(s.pixel_endx);
+
+ if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 ||
+ dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I)
{
- s.pipeline_needs_reorder = false;
+ s.pixel_startx = align_multiple_floor(s.pixel_startx, sensor.pixel_count_ratio.divisor());
+ s.pixel_endx = align_multiple_floor(s.pixel_endx, sensor.pixel_count_ratio.divisor());
}
- s.pipeline_needs_ccd = s.max_color_shift_lines + s.num_staggered_lines > 0;
- s.pipeline_needs_shrink = dev->settings.requested_pixels != s.output_pixels;
}
-void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s,
- const Genesys_Sensor& sensor)
+unsigned session_adjust_output_pixels(unsigned output_pixels,
+ const Genesys_Device& dev, const Genesys_Sensor& sensor,
+ unsigned output_xresolution, unsigned output_yresolution,
+ bool adjust_output_pixels)
{
- unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel();
-
- if (dev->model->asic_type == AsicType::GL646) {
-
- // startx cannot be below dummy pixel value
- s.pixel_startx = sensor.dummy_pixel;
- if (has_flag(s.params.flags, ScanFlag::USE_XCORRECTION) && sensor.ccd_start_xoffset > 0) {
- s.pixel_startx = sensor.ccd_start_xoffset;
- }
- s.pixel_startx += s.params.startx;
-
- if (sensor.stagger_config.stagger_at_resolution(s.params.xres, s.params.yres) > 0) {
- s.pixel_startx |= 1;
- }
-
- s.pixel_endx = s.pixel_startx + s.optical_pixels;
-
- s.pixel_startx /= sensor.ccd_pixels_per_system_pixel() * s.ccd_size_divisor;
- s.pixel_endx /= sensor.ccd_pixels_per_system_pixel() * s.ccd_size_divisor;
-
- } else if (dev->model->asic_type == AsicType::GL841) {
- s.pixel_startx = ((sensor.ccd_start_xoffset + s.params.startx) * s.optical_resolution)
- / sensor.optical_res;
+ bool adjust_optical_pixels = !adjust_output_pixels;
+ if (dev.model->model_id == ModelId::CANON_5600F) {
+ adjust_optical_pixels = true;
+ adjust_output_pixels = true;
+ }
+ if (adjust_optical_pixels) {
+ auto optical_resolution = sensor.get_optical_resolution();
- s.pixel_startx += sensor.dummy_pixel + 1;
+ // FIXME: better way would be to compute and return the required multiplier
+ unsigned optical_pixels = (output_pixels * optical_resolution) / output_xresolution;
- if (s.num_staggered_lines > 0 && (s.pixel_startx & 1) == 0) {
- s.pixel_startx++;
+ if (dev.model->asic_type == AsicType::GL841 ||
+ dev.model->asic_type == AsicType::GL842)
+ {
+ optical_pixels = align_multiple_ceil(optical_pixels, 2);
}
- /* In case of SHDAREA, we need to align start on pixel average factor, startx is
- different than 0 only when calling for function to setup for scan, where shading data
- needs to be align.
-
- NOTE: we can check the value of the register here, because we don't set this bit
- anywhere except in initialization.
- */
- const uint8_t REG_0x01_SHDAREA = 0x02;
- if ((dev->reg.find_reg(0x01).value & REG_0x01_SHDAREA) != 0) {
- unsigned average_factor = s.optical_resolution / s.params.xres;
- s.pixel_startx = align_multiple_floor(s.pixel_startx, average_factor);
+ if (dev.model->asic_type == AsicType::GL646 && output_xresolution == 400) {
+ optical_pixels = align_multiple_floor(optical_pixels, 6);
}
- s.pixel_endx = s.pixel_startx + s.optical_pixels;
-
- } else if (dev->model->asic_type == AsicType::GL843) {
-
- s.pixel_startx = (s.params.startx + sensor.dummy_pixel) / ccd_pixels_per_system_pixel;
- s.pixel_endx = s.pixel_startx + s.optical_pixels / ccd_pixels_per_system_pixel;
-
- s.pixel_startx /= s.hwdpi_divisor;
- s.pixel_endx /= s.hwdpi_divisor;
-
- // in case of stagger we have to start at an odd coordinate
- bool stagger_starts_even = dev->model->model_id == ModelId::CANON_8400F;
- if (s.num_staggered_lines > 0) {
- if (!stagger_starts_even && (s.pixel_startx & 1) == 0) {
- s.pixel_startx++;
- s.pixel_endx++;
- } else if (stagger_starts_even && (s.pixel_startx & 1) != 0) {
- s.pixel_startx++;
- s.pixel_endx++;
+ if (dev.model->asic_type == AsicType::GL843) {
+ // ensure the number of optical pixels is divisible by 2.
+ // In quarter-CCD mode optical_pixels is 4x larger than the actual physical number
+ optical_pixels = align_multiple_ceil(optical_pixels,
+ 2 * sensor.full_resolution / optical_resolution);
+ if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200 ||
+ dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
+ dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 ||
+ dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
+ dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I ||
+ dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
+ {
+ optical_pixels = align_multiple_ceil(optical_pixels, 16);
}
}
+ output_pixels = (optical_pixels * output_xresolution) / optical_resolution;
+ }
- } else if (dev->model->asic_type == AsicType::GL845 ||
- dev->model->asic_type == AsicType::GL846 ||
- dev->model->asic_type == AsicType::GL847)
- {
- s.pixel_startx = s.params.startx;
-
- if (s.num_staggered_lines > 0) {
- s.pixel_startx |= 1;
- }
-
- s.pixel_startx += sensor.ccd_start_xoffset * ccd_pixels_per_system_pixel;
- s.pixel_endx = s.pixel_startx + s.optical_pixels_raw;
-
- s.pixel_startx /= s.hwdpi_divisor * s.segment_count * ccd_pixels_per_system_pixel;
- s.pixel_endx /= s.hwdpi_divisor * s.segment_count * ccd_pixels_per_system_pixel;
-
- } else if (dev->model->asic_type == AsicType::GL124) {
- s.pixel_startx = s.params.startx;
+ if (adjust_output_pixels) {
+ // TODO: the following may no longer be needed but were applied historically.
- if (s.num_staggered_lines > 0) {
- s.pixel_startx |= 1;
+ // we need an even pixels number
+ // TODO invert test logic or generalize behaviour across all ASICs
+ if (has_flag(dev.model->flags, ModelFlag::SIS_SENSOR) ||
+ dev.model->asic_type == AsicType::GL847 ||
+ dev.model->asic_type == AsicType::GL124 ||
+ dev.model->asic_type == AsicType::GL845 ||
+ dev.model->asic_type == AsicType::GL846 ||
+ dev.model->asic_type == AsicType::GL843)
+ {
+ if (output_xresolution <= 1200) {
+ output_pixels = align_multiple_floor(output_pixels, 4);
+ } else if (output_xresolution < output_yresolution) {
+ // BUG: this is an artifact of the fact that the resolution was twice as large than
+ // the actual resolution when scanning above the supported scanner X resolution
+ output_pixels = align_multiple_floor(output_pixels, 8);
+ } else {
+ output_pixels = align_multiple_floor(output_pixels, 16);
+ }
}
- s.pixel_startx /= ccd_pixels_per_system_pixel;
- // FIXME: should we add sensor.dummy_pxel to pixel_startx at this point?
- s.pixel_endx = s.pixel_startx + s.optical_pixels / ccd_pixels_per_system_pixel;
-
- s.pixel_startx /= s.hwdpi_divisor * s.segment_count;
- s.pixel_endx /= s.hwdpi_divisor * s.segment_count;
-
- std::uint32_t segcnt = (sensor.custom_regs.get_value(gl124::REG_SEGCNT) << 16) +
- (sensor.custom_regs.get_value(gl124::REG_SEGCNT + 1) << 8) +
- sensor.custom_regs.get_value(gl124::REG_SEGCNT + 2);
- if (s.pixel_endx == segcnt) {
- s.pixel_endx = 0;
+ // corner case for true lineart for sensor with several segments or when xres is doubled
+ // to match yres */
+ if (output_xresolution >= 1200 && (
+ dev.model->asic_type == AsicType::GL124 ||
+ dev.model->asic_type == AsicType::GL847 ||
+ dev.session.params.xres < dev.session.params.yres))
+ {
+ if (output_xresolution < output_yresolution) {
+ // FIXME: this is an artifact of the fact that the resolution was twice as large than
+ // the actual resolution when scanning above the supported scanner X resolution
+ output_pixels = align_multiple_floor(output_pixels, 8);
+ } else {
+ output_pixels = align_multiple_floor(output_pixels, 16);
+ }
}
}
- s.pixel_count_multiplier = sensor.pixel_count_multiplier;
-
- s.pixel_startx *= sensor.pixel_count_multiplier;
- s.pixel_endx *= sensor.pixel_count_multiplier;
+ return output_pixels;
}
void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor)
@@ -1011,68 +927,36 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
throw SaneException("Unsupported depth setting %d", s.params.depth);
}
- unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel();
-
// compute optical and output resolutions
-
- if (dev->model->asic_type == AsicType::GL843) {
- // FIXME: this may be incorrect, but need more scanners to test
- s.hwdpi_divisor = sensor.get_hwdpi_divisor_for_dpi(s.params.xres);
- } else {
- s.hwdpi_divisor = sensor.get_hwdpi_divisor_for_dpi(s.params.xres * ccd_pixels_per_system_pixel);
- }
-
- s.ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(s.params.xres);
-
- if (dev->model->asic_type == AsicType::GL646) {
- s.optical_resolution = sensor.optical_res;
- } else {
- s.optical_resolution = sensor.optical_res / s.ccd_size_divisor;
- }
+ s.full_resolution = sensor.full_resolution;
+ s.optical_resolution = sensor.get_optical_resolution();
s.output_resolution = s.params.xres;
+ s.pixel_count_ratio = sensor.pixel_count_ratio;
+
if (s.output_resolution > s.optical_resolution) {
throw std::runtime_error("output resolution higher than optical resolution");
}
- // compute the number of optical pixels that will be acquired by the chip
- s.optical_pixels = (s.params.pixels * s.optical_resolution) / s.output_resolution;
- if (s.optical_pixels * s.output_resolution < s.params.pixels * s.optical_resolution) {
- s.optical_pixels++;
- }
-
- if (dev->model->asic_type == AsicType::GL841) {
- if (s.optical_pixels & 1)
- s.optical_pixels++;
- }
-
- if (dev->model->asic_type == AsicType::GL646 && s.params.xres == 400) {
- s.optical_pixels = (s.optical_pixels / 6) * 6;
- }
+ s.output_pixels = session_adjust_output_pixels(s.params.pixels, *dev, sensor,
+ s.params.xres, s.params.yres, false);
- if (dev->model->asic_type == AsicType::GL843) {
- // ensure the number of optical pixels is divisible by 2.
- // In quarter-CCD mode optical_pixels is 4x larger than the actual physical number
- s.optical_pixels = align_int_up(s.optical_pixels, 2 * s.ccd_size_divisor);
+ // Compute the number of optical pixels that will be acquired by the chip.
+ // The necessary alignment requirements have already been computed by
+ // get_session_output_pixels_multiplier
+ s.optical_pixels = (s.output_pixels * s.optical_resolution) / s.output_resolution;
- if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
- dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 ||
- dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I)
- {
- s.optical_pixels = align_int_up(s.optical_pixels, 16);
- }
- }
+ if (static_cast<int>(s.params.startx) + sensor.output_pixel_offset < 0)
+ throw SaneException("Invalid sensor.output_pixel_offset");
+ s.output_startx = static_cast<unsigned>(
+ static_cast<int>(s.params.startx) + sensor.output_pixel_offset);
- // after all adjustments on the optical pixels have been made, compute the number of pixels
- // to retrieve from the chip
- s.output_pixels = (s.optical_pixels * s.output_resolution) / s.optical_resolution;
+ s.stagger_x = sensor.stagger_x;
+ s.stagger_y = sensor.stagger_y;
- // Note: staggering is not applied for calibration. Staggering starts at 2400 dpi
s.num_staggered_lines = 0;
- if (!has_flag(s.params.flags, ScanFlag::IGNORE_LINE_DISTANCE))
- {
- s.num_staggered_lines = sensor.stagger_config.stagger_at_resolution(s.params.xres,
- s.params.yres);
+ if (!has_flag(s.params.flags, ScanFlag::IGNORE_STAGGER_OFFSET)) {
+ s.num_staggered_lines = s.stagger_y.max_shift() * s.params.yres / s.params.xres;
}
s.color_shift_lines_r = dev->model->ld_shift_r;
@@ -1091,12 +975,14 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
s.color_shift_lines_b = (s.color_shift_lines_b * s.params.yres) / dev->motor.base_ydpi;
s.max_color_shift_lines = 0;
- if (s.params.channels > 1 && !has_flag(s.params.flags, ScanFlag::IGNORE_LINE_DISTANCE)) {
+ if (s.params.channels > 1 && !has_flag(s.params.flags, ScanFlag::IGNORE_COLOR_OFFSET)) {
s.max_color_shift_lines = std::max(s.color_shift_lines_r, std::max(s.color_shift_lines_g,
s.color_shift_lines_b));
}
s.output_line_count = s.params.lines + s.max_color_shift_lines + s.num_staggered_lines;
+ s.optical_line_count = dev->model->is_cis ? s.output_line_count * s.params.channels
+ : s.output_line_count;
s.output_channel_bytes = multiply_by_depth_ceil(s.output_pixels, s.params.depth);
s.output_line_bytes = s.output_channel_bytes * s.params.channels;
@@ -1107,29 +993,62 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
s.output_line_bytes_raw = s.output_line_bytes;
s.conseq_pixel_dist = 0;
- if (dev->model->asic_type == AsicType::GL845 ||
- dev->model->asic_type == AsicType::GL846 ||
- dev->model->asic_type == AsicType::GL847)
+ // FIXME: Use ModelFlag::SIS_SENSOR
+ if ((dev->model->asic_type == AsicType::GL845 ||
+ dev->model->asic_type == AsicType::GL846 ||
+ dev->model->asic_type == AsicType::GL847) &&
+ dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7400 &&
+ dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_8200I)
{
if (s.segment_count > 1) {
s.conseq_pixel_dist = sensor.segment_size;
- // in case of multi-segments sensor, we have to add the width of the sensor crossed by
- // the scan area
- unsigned extra_segment_scan_area = align_multiple_ceil(s.conseq_pixel_dist, 2);
- extra_segment_scan_area *= s.segment_count - 1;
- extra_segment_scan_area *= s.hwdpi_divisor * s.segment_count;
- extra_segment_scan_area *= ccd_pixels_per_system_pixel;
+ // in case of multi-segments sensor, we have expand the scan area to sensor boundary
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ unsigned startx_xres = s.optical_resolution;
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ if (s.output_resolution == 1200) {
+ startx_xres /= 2;
+ }
+ if (s.output_resolution >= 2400) {
+ startx_xres /= 4;
+ }
+ }
+ unsigned optical_startx = s.output_startx * startx_xres / s.params.xres;
+ unsigned optical_endx = optical_startx + s.optical_pixels;
- s.optical_pixels_raw += extra_segment_scan_area;
+ unsigned multi_segment_size_output = s.segment_count * s.conseq_pixel_dist;
+ unsigned multi_segment_size_optical =
+ (multi_segment_size_output * s.optical_resolution) / s.output_resolution;
+
+ optical_endx = align_multiple_ceil(optical_endx, multi_segment_size_optical);
+ s.optical_pixels_raw = optical_endx - optical_startx;
+ s.optical_pixels_raw = align_multiple_floor(s.optical_pixels_raw,
+ 4 * s.optical_resolution / s.output_resolution);
+ } else {
+ // BUG: the following code will likely scan too much. Use the CANON_5600F approach
+ unsigned extra_segment_scan_area = align_multiple_ceil(s.conseq_pixel_dist, 2);
+ extra_segment_scan_area *= s.segment_count - 1;
+ extra_segment_scan_area = s.pixel_count_ratio.apply_inverse(extra_segment_scan_area);
+
+ s.optical_pixels_raw += extra_segment_scan_area;
+ }
}
- s.output_line_bytes_raw = multiply_by_depth_ceil(
- (s.optical_pixels_raw * s.output_resolution) / sensor.optical_res / s.segment_count,
- s.params.depth);
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ auto output_pixels_raw = (s.optical_pixels_raw * s.output_resolution) / s.optical_resolution;
+ auto output_channel_bytes_raw = multiply_by_depth_ceil(output_pixels_raw, s.params.depth);
+ s.output_line_bytes_raw = output_channel_bytes_raw * s.params.channels;
+ } else {
+ s.output_line_bytes_raw = multiply_by_depth_ceil(
+ (s.optical_pixels_raw * s.output_resolution) / sensor.full_resolution / s.segment_count,
+ s.params.depth);
+ }
}
- if (dev->model->asic_type == AsicType::GL841) {
+ if (dev->model->asic_type == AsicType::GL841 ||
+ dev->model->asic_type == AsicType::GL842)
+ {
if (dev->model->is_cis) {
s.output_line_bytes_raw = s.output_channel_bytes;
}
@@ -1139,27 +1058,43 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
if (dev->model->is_cis) {
s.output_line_bytes_raw = s.output_channel_bytes;
}
- s.conseq_pixel_dist = s.output_pixels / s.ccd_size_divisor / s.segment_count;
+ s.conseq_pixel_dist = s.output_pixels / (s.full_resolution / s.optical_resolution) / s.segment_count;
}
- if (dev->model->asic_type == AsicType::GL843) {
- s.conseq_pixel_dist = s.output_pixels / s.segment_count;
+ if (dev->model->asic_type == AsicType::GL842 ||
+ dev->model->asic_type == AsicType::GL843)
+ {
+ if (dev->model->is_cis) {
+ if (s.segment_count > 1) {
+ s.conseq_pixel_dist = sensor.segment_size;
+ }
+ } else {
+ s.conseq_pixel_dist = s.output_pixels / s.segment_count;
+ }
}
s.output_segment_pixel_group_count = 0;
if (dev->model->asic_type == AsicType::GL124 ||
+ dev->model->asic_type == AsicType::GL842 ||
dev->model->asic_type == AsicType::GL843)
{
- s.output_segment_pixel_group_count = multiply_by_depth_ceil(
- s.output_pixels / s.ccd_size_divisor / s.segment_count, s.params.depth);
+ s.output_segment_pixel_group_count = s.output_pixels /
+ (s.full_resolution / s.optical_resolution * s.segment_count);
}
+
+ if (dev->model->model_id == ModelId::CANON_LIDE_90) {
+ s.output_segment_pixel_group_count = s.output_pixels / s.segment_count;
+ }
+
if (dev->model->asic_type == AsicType::GL845 ||
dev->model->asic_type == AsicType::GL846 ||
dev->model->asic_type == AsicType::GL847)
{
- s.output_segment_pixel_group_count = multiply_by_depth_ceil(
- s.optical_pixels / (s.hwdpi_divisor * s.segment_count * ccd_pixels_per_system_pixel),
- s.params.depth);
+ if (dev->model->model_id == ModelId::CANON_5600F) {
+ s.output_segment_pixel_group_count = s.output_pixels / s.segment_count;
+ } else {
+ s.output_segment_pixel_group_count = s.pixel_count_ratio.apply(s.optical_pixels);
+ }
}
s.output_line_bytes_requested = multiply_by_depth_ceil(
@@ -1167,11 +1102,16 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
s.output_total_bytes_raw = s.output_line_bytes_raw * s.output_line_count;
s.output_total_bytes = s.output_line_bytes * s.output_line_count;
+ if (dev->model->model_id == ModelId::CANON_LIDE_90) {
+ s.output_total_bytes_raw *= s.params.channels;
+ s.output_total_bytes *= s.params.channels;
+ }
- compute_session_buffer_sizes(dev->model->asic_type, s);
- compute_session_pipeline(dev, s);
+ s.buffer_size_read = s.output_line_bytes_raw * 64;
compute_session_pixel_offsets(dev, s, sensor);
+ s.shading_pixel_offset = sensor.shading_pixel_offset;
+
if (dev->model->asic_type == AsicType::GL124 ||
dev->model->asic_type == AsicType::GL845 ||
dev->model->asic_type == AsicType::GL846)
@@ -1179,7 +1119,10 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
s.enable_ledadd = (s.params.channels == 1 && dev->model->is_cis && dev->settings.true_gray);
}
+ s.use_host_side_calib = sensor.use_host_side_calib;
+
if (dev->model->asic_type == AsicType::GL841 ||
+ dev->model->asic_type == AsicType::GL842 ||
dev->model->asic_type == AsicType::GL843)
{
// no 16 bit gamma for this ASIC
@@ -1194,177 +1137,166 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
debug_dump(DBG_info, s);
}
-static std::size_t get_usb_buffer_read_size(AsicType asic, const ScanSession& session)
+ImagePipelineStack build_image_pipeline(const Genesys_Device& dev, const ScanSession& session,
+ unsigned pipeline_index, bool log_image_data)
{
- switch (asic) {
- case AsicType::GL646:
- // buffer not used on this chip set
- return 1;
-
- case AsicType::GL124:
- // BUG: we shouldn't multiply by channels here nor divide by ccd_size_divisor
- return session.output_line_bytes_raw / session.ccd_size_divisor * session.params.channels;
-
- case AsicType::GL845:
- case AsicType::GL846:
- case AsicType::GL847:
- // BUG: we shouldn't multiply by channels here
- return session.output_line_bytes_raw * session.params.channels;
-
- case AsicType::GL843:
- return session.output_line_bytes_raw * 2;
-
- default:
- throw SaneException("Unknown asic type");
- }
-}
-
-static FakeBufferModel get_fake_usb_buffer_model(const ScanSession& session)
-{
- FakeBufferModel model;
- model.push_step(session.buffer_size_read, 1);
-
- if (session.pipeline_needs_reorder) {
- model.push_step(session.buffer_size_lines, session.output_line_bytes);
- }
- if (session.pipeline_needs_ccd) {
- model.push_step(session.buffer_size_shrink, session.output_line_bytes);
- }
- if (session.pipeline_needs_shrink) {
- model.push_step(session.buffer_size_out, session.output_line_bytes);
- }
-
- return model;
-}
-
-void build_image_pipeline(Genesys_Device* dev, const ScanSession& session)
-{
- static unsigned s_pipeline_index = 0;
-
- s_pipeline_index++;
-
auto format = create_pixel_format(session.params.depth,
- dev->model->is_cis ? 1 : session.params.channels,
- dev->model->line_mode_color_order);
+ dev.model->is_cis ? 1 : session.params.channels,
+ dev.model->line_mode_color_order);
auto depth = get_pixel_format_depth(format);
auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw);
- auto read_data_from_usb = [dev](std::size_t size, std::uint8_t* data)
+ auto read_data_from_usb = [&dev](std::size_t size, std::uint8_t* data)
{
- dev->interface->bulk_read_data(0x45, data, size);
+ DBG(DBG_info, "read_data_from_usb: reading %zu bytes\n", size);
+ auto begin = std::chrono::high_resolution_clock::now();
+ dev.interface->bulk_read_data(0x45, data, size);
+ auto end = std::chrono::high_resolution_clock::now();
+ float us = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count();
+ float speed = size / us; // bytes/us == MB/s
+ DBG(DBG_info, "read_data_from_usb: reading %zu bytes finished %f MB/s\n", size, speed);
return true;
};
- auto lines = session.output_line_count * (dev->model->is_cis ? session.params.channels : 1);
+ auto debug_prefix = "gl_pipeline_" + std::to_string(pipeline_index);
- dev->pipeline.clear();
+ ImagePipelineStack pipeline;
- // FIXME: here we are complicating things for the time being to preserve the existing behaviour
- // This allows to be sure that the changes to the image pipeline have not introduced
- // regressions.
+ auto lines = session.optical_line_count;
+ auto buffer_size = session.buffer_size_read;
- if (session.segment_count > 1) {
- // BUG: we're reading one line too much
- dev->pipeline.push_first_node<ImagePipelineNodeBufferedCallableSource>(
- width, lines + 1, format,
- get_usb_buffer_read_size(dev->model->asic_type, session), read_data_from_usb);
+ // At least GL841 requires reads to be aligned to 2 bytes and will fail on some devices on
+ // certain circumstances.
+ buffer_size = align_multiple_ceil(buffer_size, 2);
+
+ auto& src_node = pipeline.push_first_node<ImagePipelineNodeBufferedCallableSource>(
+ width, lines, format, buffer_size, read_data_from_usb);
+ src_node.set_last_read_multiple(2);
+ if (log_image_data) {
+ pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_0_from_usb.tiff");
+ }
+
+ if (session.segment_count > 1) {
auto output_width = session.output_segment_pixel_group_count * session.segment_count;
- dev->pipeline.push_node<ImagePipelineNodeDesegment>(output_width, dev->segment_order,
+ pipeline.push_node<ImagePipelineNodeDesegment>(output_width, dev.segment_order,
session.conseq_pixel_dist,
1, 1);
- } else {
- auto read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count;
- if (dev->model->asic_type == AsicType::GL646) {
- read_bytes_left_after_deseg *= dev->model->is_cis ? session.params.channels : 1;
- }
- dev->pipeline.push_first_node<ImagePipelineNodeBufferedGenesysUsb>(
- width, lines, format, read_bytes_left_after_deseg,
- get_fake_usb_buffer_model(session), read_data_from_usb);
+ if (log_image_data) {
+ pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_1_after_desegment.tiff");
+ }
}
- if (DBG_LEVEL >= DBG_io2) {
- dev->pipeline.push_node<ImagePipelineNodeDebug>("gl_pipeline_" +
- std::to_string(s_pipeline_index) +
- "_0_before_swap.pnm");
- }
+ if (depth == 16) {
+ unsigned num_swaps = 0;
+ if (has_flag(dev.model->flags, ModelFlag::SWAP_16BIT_DATA)) {
+ num_swaps++;
+ }
+#ifdef WORDS_BIGENDIAN
+ num_swaps++;
+#endif
+ if (num_swaps % 2 != 0) {
+ pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
- if ((dev->model->flags & GENESYS_FLAG_16BIT_DATA_INVERTED) && depth == 16) {
- dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
+ if (log_image_data) {
+ pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_2_after_swap.tiff");
+ }
+ }
}
-#ifdef WORDS_BIGENDIAN
- if (depth == 16) {
- dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
+ if (has_flag(dev.model->flags, ModelFlag::INVERT_PIXEL_DATA)) {
+ pipeline.push_node<ImagePipelineNodeInvert>();
+
+ if (log_image_data) {
+ pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_3_after_invert.tiff");
+ }
}
-#endif
- if (DBG_LEVEL >= DBG_io2) {
- dev->pipeline.push_node<ImagePipelineNodeDebug>("gl_pipeline_" +
- std::to_string(s_pipeline_index) +
- "_1_after_swap.pnm");
+ if (dev.model->is_cis && session.params.channels == 3) {
+ pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev.model->line_mode_color_order);
+
+ if (log_image_data) {
+ pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_4_after_merge_mono.tiff");
+ }
}
- if (dev->model->is_cis && session.params.channels == 3) {
- dev->pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev->model->line_mode_color_order);
+ if (pipeline.get_output_format() == PixelFormat::BGR888) {
+ pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
}
- if (dev->pipeline.get_output_format() == PixelFormat::BGR888) {
- dev->pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
+ if (pipeline.get_output_format() == PixelFormat::BGR161616) {
+ pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
}
- if (dev->pipeline.get_output_format() == PixelFormat::BGR161616) {
- dev->pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
+ if (log_image_data) {
+ pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_5_after_format.tiff");
}
if (session.max_color_shift_lines > 0 && session.params.channels == 3) {
- dev->pipeline.push_node<ImagePipelineNodeComponentShiftLines>(
+ pipeline.push_node<ImagePipelineNodeComponentShiftLines>(
session.color_shift_lines_r,
session.color_shift_lines_g,
session.color_shift_lines_b);
+
+ if (log_image_data) {
+ pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_6_after_color_unshift.tiff");
+ }
}
- if (DBG_LEVEL >= DBG_io2) {
- dev->pipeline.push_node<ImagePipelineNodeDebug>("gl_pipeline_" +
- std::to_string(s_pipeline_index) +
- "_2_after_shift.pnm");
+ if (!session.stagger_x.empty()) {
+ // FIXME: the image will be scaled to requested pixel count without regard to the reduction
+ // of image size in this step.
+ pipeline.push_node<ImagePipelineNodePixelShiftColumns>(session.stagger_x.shifts());
+
+ if (log_image_data) {
+ pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_7_after_x_unstagger.tiff");
+ }
}
if (session.num_staggered_lines > 0) {
- std::vector<std::size_t> shifts{0, session.num_staggered_lines};
- dev->pipeline.push_node<ImagePipelineNodePixelShiftLines>(shifts);
- }
+ pipeline.push_node<ImagePipelineNodePixelShiftLines>(session.stagger_y.shifts());
- if (DBG_LEVEL >= DBG_io2) {
- dev->pipeline.push_node<ImagePipelineNodeDebug>("gl_pipeline_" +
- std::to_string(s_pipeline_index) +
- "_3_after_stagger.pnm");
+ if (log_image_data) {
+ pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_8_after_y_unstagger.tiff");
+ }
}
- if ((dev->model->flags & GENESYS_FLAG_CALIBRATION_HOST_SIDE) &&
- !(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION))
+ if (session.use_host_side_calib &&
+ !has_flag(dev.model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) &&
+ !has_flag(session.params.flags, ScanFlag::DISABLE_SHADING))
{
- dev->pipeline.push_node<ImagePipelineNodeCalibrate>(dev->dark_average_data,
- dev->white_average_data);
+ unsigned offset_pixels = session.params.startx + dev.calib_session.shading_pixel_offset;
+ unsigned offset_bytes = offset_pixels * dev.calib_session.params.channels;
+ pipeline.push_node<ImagePipelineNodeCalibrate>(dev.dark_average_data,
+ dev.white_average_data, offset_bytes);
- if (DBG_LEVEL >= DBG_io2) {
- dev->pipeline.push_node<ImagePipelineNodeDebug>("gl_pipeline_" +
- std::to_string(s_pipeline_index) +
- "_4_after_calibrate.pnm");
+ if (log_image_data) {
+ pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_9_after_calibrate.tiff");
}
}
- if (session.output_pixels != session.params.get_requested_pixels()) {
- dev->pipeline.push_node<ImagePipelineNodeScaleRows>(session.params.get_requested_pixels());
+ if (pipeline.get_output_width() != session.params.get_requested_pixels()) {
+ pipeline.push_node<ImagePipelineNodeScaleRows>(session.params.get_requested_pixels());
}
- auto read_from_pipeline = [dev](std::size_t size, std::uint8_t* out_data)
+ return pipeline;
+}
+
+void setup_image_pipeline(Genesys_Device& dev, const ScanSession& session)
+{
+ static unsigned s_pipeline_index = 0;
+
+ s_pipeline_index++;
+
+ dev.pipeline = build_image_pipeline(dev, session, s_pipeline_index, dbg_log_image_data());
+
+ auto read_from_pipeline = [&dev](std::size_t size, std::uint8_t* out_data)
{
- (void) size; // will be always equal to dev->pipeline.get_output_row_bytes()
- return dev->pipeline.get_next_row_data(out_data);
+ (void) size; // will be always equal to dev.pipeline.get_output_row_bytes()
+ return dev.pipeline.get_next_row_data(out_data);
};
- dev->pipeline_buffer = ImageBuffer{dev->pipeline.get_output_row_bytes(),
+ dev.pipeline_buffer = ImageBuffer{dev.pipeline.get_output_row_bytes(),
read_from_pipeline};
}
@@ -1394,6 +1326,32 @@ std::uint8_t compute_frontend_gain_wolfson(float value, float target_value)
return clamp(code, 0, 255);
}
+std::uint8_t compute_frontend_gain_lide_80(float value, float target_value)
+{
+ int code = static_cast<int>((target_value / value) * 12);
+ return clamp(code, 0, 255);
+}
+
+std::uint8_t compute_frontend_gain_wolfson_gl841(float value, float target_value)
+{
+ // this code path is similar to what generic wolfson code path uses and uses similar constants,
+ // but is likely incorrect.
+ float inv_gain = target_value / value;
+ inv_gain *= 0.69f;
+ int code = static_cast<int>(283 - 208 / inv_gain);
+ return clamp(code, 0, 255);
+}
+
+std::uint8_t compute_frontend_gain_wolfson_gl846_gl847_gl124(float value, float target_value)
+{
+ // this code path is similar to what generic wolfson code path uses and uses similar constants,
+ // but is likely incorrect.
+ float inv_gain = target_value / value;
+ int code = static_cast<int>(283 - 208 / inv_gain);
+ return clamp(code, 0, 255);
+}
+
+
std::uint8_t compute_frontend_gain_analog_devices(float value, float target_value)
{
/* The flow of data through the frontend ADC is as follows (see e.g. AD9826 datasheet)
@@ -1418,13 +1376,22 @@ std::uint8_t compute_frontend_gain_analog_devices(float value, float target_valu
std::uint8_t compute_frontend_gain(float value, float target_value,
FrontendType frontend_type)
{
- if (frontend_type == FrontendType::WOLFSON) {
- return compute_frontend_gain_wolfson(value, target_value);
- }
- if (frontend_type == FrontendType::ANALOG_DEVICES) {
- return compute_frontend_gain_analog_devices(value, target_value);
+ switch (frontend_type) {
+ case FrontendType::WOLFSON:
+ return compute_frontend_gain_wolfson(value, target_value);
+ case FrontendType::ANALOG_DEVICES:
+ return compute_frontend_gain_analog_devices(value, target_value);
+ case FrontendType::CANON_LIDE_80:
+ return compute_frontend_gain_lide_80(value, target_value);
+ case FrontendType::WOLFSON_GL841:
+ return compute_frontend_gain_wolfson_gl841(value, target_value);
+ case FrontendType::WOLFSON_GL846:
+ case FrontendType::ANALOG_DEVICES_GL847:
+ case FrontendType::WOLFSON_GL124:
+ return compute_frontend_gain_wolfson_gl846_gl847_gl124(value, target_value);
+ default:
+ throw SaneException("Unknown frontend to compute gain for");
}
- throw SaneException("Unknown frontend to compute gain for");
}
/** @brief initialize device
@@ -1436,7 +1403,7 @@ std::uint8_t compute_frontend_gain(float value, float target_value,
* @param dev device to initialize
* @param max_regs umber of maximum used registers
*/
-void sanei_genesys_asic_init(Genesys_Device* dev, bool /*max_regs*/)
+void sanei_genesys_asic_init(Genesys_Device* dev)
{
DBG_HELPER(dbg);
@@ -1486,8 +1453,7 @@ void sanei_genesys_asic_init(Genesys_Device* dev, bool /*max_regs*/)
dev->settings.color_filter = ColorFilter::RED;
- /* duplicate initial values into calibration registers */
- dev->calib_reg = dev->reg;
+ dev->initial_regs = dev->reg;
const auto& sensor = sanei_genesys_find_sensor_any(dev);
@@ -1497,8 +1463,15 @@ void sanei_genesys_asic_init(Genesys_Device* dev, bool /*max_regs*/)
dev->already_initialized = true;
// Move to home if needed
+ if (dev->model->model_id == ModelId::CANON_8600F) {
+ if (!dev->cmd_set->is_head_home(*dev, ScanHeadId::SECONDARY)) {
+ dev->set_head_pos_unknown(ScanHeadId::SECONDARY);
+ }
+ if (!dev->cmd_set->is_head_home(*dev, ScanHeadId::PRIMARY)) {
+ dev->set_head_pos_unknown(ScanHeadId::SECONDARY);
+ }
+ }
dev->cmd_set->move_back_home(dev, true);
- dev->set_head_pos_zero(ScanHeadId::PRIMARY);
// Set powersaving (default = 15 minutes)
dev->cmd_set->set_powersaving(dev, 15);
@@ -1510,6 +1483,7 @@ void scanner_start_action(Genesys_Device& dev, bool start_motor)
switch (dev.model->asic_type) {
case AsicType::GL646:
case AsicType::GL841:
+ case AsicType::GL842:
case AsicType::GL843:
case AsicType::GL845:
case AsicType::GL846:
@@ -1527,8 +1501,7 @@ void scanner_start_action(Genesys_Device& dev, bool start_motor)
}
}
-void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, const Genesys_Sensor& sensor,
- unsigned dpihw)
+void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, unsigned dpihw)
{
// same across GL646, GL841, GL843, GL846, GL847, GL124
const uint8_t REG_0x05_DPIHW_MASK = 0xc0;
@@ -1537,10 +1510,6 @@ void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, const Genesys_Sensor& s
const uint8_t REG_0x05_DPIHW_2400 = 0x80;
const uint8_t REG_0x05_DPIHW_4800 = 0xc0;
- if (sensor.register_dpihw_override != 0) {
- dpihw = sensor.register_dpihw_override;
- }
-
uint8_t dpihw_setting;
switch (dpihw) {
case 600:
@@ -1583,6 +1552,12 @@ void regs_set_exposure(AsicType asic_type, Genesys_Register_Set& regs,
regs.set16(gl841::REG_EXPB, exposure.blue);
break;
}
+ case AsicType::GL842: {
+ regs.set16(gl842::REG_EXPR, exposure.red);
+ regs.set16(gl842::REG_EXPG, exposure.green);
+ regs.set16(gl842::REG_EXPB, exposure.blue);
+ break;
+ }
case AsicType::GL843: {
regs.set16(gl843::REG_EXPR, exposure.red);
regs.set16(gl843::REG_EXPG, exposure.green);
@@ -1619,6 +1594,10 @@ void regs_set_optical_off(AsicType asic_type, Genesys_Register_Set& regs)
regs.find_reg(gl841::REG_0x01).value &= ~gl841::REG_0x01_SCAN;
break;
}
+ case AsicType::GL842: {
+ regs.find_reg(gl842::REG_0x01).value &= ~gl842::REG_0x01_SCAN;
+ break;
+ }
case AsicType::GL843: {
regs.find_reg(gl843::REG_0x01).value &= ~gl843::REG_0x01_SCAN;
break;
@@ -1648,6 +1627,8 @@ bool get_registers_gain4_bit(AsicType asic_type, const Genesys_Register_Set& reg
return static_cast<bool>(regs.get8(gl646::REG_0x06) & gl646::REG_0x06_GAIN4);
case AsicType::GL841:
return static_cast<bool>(regs.get8(gl841::REG_0x06) & gl841::REG_0x06_GAIN4);
+ case AsicType::GL842:
+ return static_cast<bool>(regs.get8(gl842::REG_0x06) & gl842::REG_0x06_GAIN4);
case AsicType::GL843:
return static_cast<bool>(regs.get8(gl843::REG_0x06) & gl843::REG_0x06_GAIN4);
case AsicType::GL845:
@@ -1706,79 +1687,78 @@ void sanei_genesys_wait_for_home(Genesys_Device* dev)
}
}
-/** @brief motor profile
- * search for the database of motor profiles and get the best one. Each
- * profile is at full step and at a reference exposure. Use first entry
- * by default.
- * @param motors motor profile database
- * @param motor_type motor id
- * @param exposure exposure time
- * @return a pointer to a Motor_Profile struct
- */
-const Motor_Profile& sanei_genesys_get_motor_profile(const std::vector<Motor_Profile>& motors,
- MotorId motor_id, int exposure)
+const MotorProfile* get_motor_profile_ptr(const std::vector<MotorProfile>& profiles,
+ unsigned exposure,
+ const ScanSession& session)
{
- int idx;
+ int best_i = -1;
+
+ for (unsigned i = 0; i < profiles.size(); ++i) {
+ const auto& profile = profiles[i];
- idx=-1;
- for (std::size_t i = 0; i < motors.size(); ++i) {
- // exact match
- if (motors[i].motor_id == motor_id && motors[i].exposure==exposure) {
- return motors[i];
+ if (!profile.resolutions.matches(session.params.yres)) {
+ continue;
+ }
+ if (!profile.scan_methods.matches(session.params.scan_method)) {
+ continue;
}
- // closest match
- if (motors[i].motor_id == motor_id) {
- /* if profile exposure is higher than the required one,
- * the entry is a candidate for the closest match */
- if (motors[i].exposure == 0 || motors[i].exposure >= exposure)
- {
- if(idx<0)
- {
- /* no match found yet */
- idx=i;
- }
- else
- {
- /* test for better match */
- if(motors[i].exposure<motors[idx].exposure)
- {
- idx=i;
- }
+ if (profile.max_exposure == exposure) {
+ return &profile;
+ }
+
+ if (profile.max_exposure == 0 || profile.max_exposure >= exposure) {
+ if (best_i < 0) {
+ // no match found yet
+ best_i = i;
+ } else {
+ // test for better match
+ if (profiles[i].max_exposure < profiles[best_i].max_exposure) {
+ best_i = i;
}
}
}
}
- /* default fallback */
- if(idx<0)
- {
- DBG (DBG_warn,"%s: using default motor profile\n",__func__);
- idx=0;
+ if (best_i < 0) {
+ return nullptr;
+ }
+
+ return &profiles[best_i];
+}
+
+const MotorProfile& get_motor_profile(const std::vector<MotorProfile>& profiles,
+ unsigned exposure,
+ const ScanSession& session)
+{
+ const auto* profile = get_motor_profile_ptr(profiles, exposure, session);
+ if (profile == nullptr) {
+ throw SaneException("Motor slope is not configured");
}
- return motors[idx];
+ return *profile;
}
-MotorSlopeTable sanei_genesys_slope_table(AsicType asic_type, int dpi, int exposure, int base_dpi,
- unsigned step_multiplier,
- const Motor_Profile& motor_profile)
+MotorSlopeTable create_slope_table(AsicType asic_type, const Genesys_Motor& motor, unsigned ydpi,
+ unsigned exposure, unsigned step_multiplier,
+ const MotorProfile& motor_profile)
{
- unsigned target_speed_w = ((exposure * dpi) / base_dpi);
+ unsigned target_speed_w = ((exposure * ydpi) / motor.base_ydpi);
- auto table = create_slope_table(motor_profile.slope, target_speed_w, motor_profile.step_type,
- step_multiplier, 2 * step_multiplier,
- get_slope_table_max_size(asic_type));
+ auto table = create_slope_table_for_speed(motor_profile.slope, target_speed_w,
+ motor_profile.step_type,
+ step_multiplier, 2 * step_multiplier,
+ get_slope_table_max_size(asic_type));
return table;
}
MotorSlopeTable create_slope_table_fastest(AsicType asic_type, unsigned step_multiplier,
- const Motor_Profile& motor_profile)
+ const MotorProfile& motor_profile)
{
- return create_slope_table(motor_profile.slope, motor_profile.slope.max_speed_w,
- motor_profile.step_type,
- step_multiplier, 2 * step_multiplier,
- get_slope_table_max_size(asic_type));
+ return create_slope_table_for_speed(motor_profile.slope, motor_profile.slope.max_speed_w,
+ motor_profile.step_type,
+ step_multiplier, 2 * step_multiplier,
+ get_slope_table_max_size(asic_type));
}
/** @brief returns the lowest possible ydpi for the device
diff --git a/backend/genesys/low.h b/backend/genesys/low.h
index d7f5dd2..d67b427 100644
--- a/backend/genesys/low.h
+++ b/backend/genesys/low.h
@@ -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;
+
+ 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}
+ {}
- 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, 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);
@@ -259,21 +220,26 @@ void scanner_read_print_status(Genesys_Device& dev);
void debug_print_status(DebugMessageHelper& dbg, Status status);
+void scanner_register_rw_clear_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask);
+void scanner_register_rw_set_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask);
+void scanner_register_rw_bits(Genesys_Device& dev, std::uint16_t address,
+ std::uint8_t value, std::uint8_t mask);
+
extern void sanei_genesys_write_ahb(Genesys_Device* dev, uint32_t addr, uint32_t size,
uint8_t* data);
extern void sanei_genesys_init_structs (Genesys_Device * dev);
-const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev);
-const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, unsigned dpi,
+const Genesys_Sensor& sanei_genesys_find_sensor_any(const Genesys_Device* dev);
+const Genesys_Sensor& sanei_genesys_find_sensor(const Genesys_Device* dev, unsigned dpi,
unsigned channels, ScanMethod scan_method);
-bool sanei_genesys_has_sensor(Genesys_Device* dev, unsigned dpi, unsigned channels,
+bool sanei_genesys_has_sensor(const Genesys_Device* dev, unsigned dpi, unsigned channels,
ScanMethod scan_method);
Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, unsigned dpi,
unsigned channels, ScanMethod scan_method);
std::vector<std::reference_wrapper<const Genesys_Sensor>>
- sanei_genesys_find_sensors_all(Genesys_Device* dev, ScanMethod scan_method);
+ sanei_genesys_find_sensors_all(const Genesys_Device* dev, ScanMethod scan_method);
std::vector<std::reference_wrapper<Genesys_Sensor>>
sanei_genesys_find_sensors_all_for_write(Genesys_Device* dev, ScanMethod scan_method);
@@ -318,13 +284,9 @@ extern void sanei_genesys_set_buffer_address(Genesys_Device* dev, uint32_t addr)
unsigned sanei_genesys_get_bulk_max_size(AsicType asic_type);
-SANE_Int sanei_genesys_exposure_time2(Genesys_Device * dev, float ydpi, StepType step_type,
+SANE_Int sanei_genesys_exposure_time2(Genesys_Device* dev, const MotorProfile& profile, float ydpi,
int endpixel, int led_exposure);
-MotorSlopeTable sanei_genesys_create_slope_table3(AsicType asic_type, const Genesys_Motor& motor,
- StepType step_type, int exposure_time,
- unsigned yres);
-
void sanei_genesys_create_default_gamma_table(Genesys_Device* dev,
std::vector<uint16_t>& gamma_table, float gamma);
@@ -335,28 +297,42 @@ 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);
-void scanner_clear_scan_and_feed_counts(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.
-extern void sanei_genesys_write_file(const char* filename, const std::uint8_t* data,
- std::size_t length);
+ @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);
-extern void sanei_genesys_write_pnm_file(const char* filename, const std::uint8_t* data, int depth,
- int channels, int pixels_per_line, int lines);
+void 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 sanei_genesys_write_pnm_file(const char* filename, const Image& image);
+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_pnm_file16(const char* filename, const uint16_t *data, unsigned channels,
- unsigned pixels_per_line, unsigned lines);
+extern void sanei_genesys_write_file(const char* filename, const std::uint8_t* data,
+ std::size_t length);
void wait_until_buffer_non_empty(Genesys_Device* dev, bool check_status_twice = false);
@@ -370,25 +346,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 +360,7 @@ bool get_registers_gain4_bit(AsicType asic_type, const Genesys_Register_Set& reg
extern void sanei_genesys_wait_for_home(Genesys_Device* dev);
-extern void sanei_genesys_asic_init(Genesys_Device* dev, bool cold);
+extern void sanei_genesys_asic_init(Genesys_Device* dev);
void scanner_start_action(Genesys_Device& dev, bool start_motor);
void scanner_stop_action(Genesys_Device& dev);
@@ -404,15 +368,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);
+
+const MotorProfile* get_motor_profile_ptr(const std::vector<MotorProfile>& profiles,
+ unsigned exposure,
+ const ScanSession& session);
-MotorSlopeTable sanei_genesys_slope_table(AsicType asic_type, int dpi, int exposure, int base_dpi,
- unsigned step_multiplier,
- const Motor_Profile& motor_profile);
+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
@@ -449,52 +421,22 @@ extern void sanei_genesys_generate_gamma_buffer(Genesys_Device* dev,
int size,
uint8_t* gamma);
+unsigned session_adjust_output_pixels(unsigned output_pixels,
+ const Genesys_Device& dev, const Genesys_Sensor& sensor,
+ unsigned output_xresolution, unsigned output_yresolution,
+ bool adjust_output_pixels);
+
void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor);
-void build_image_pipeline(Genesys_Device* dev, const ScanSession& session);
+ImagePipelineStack build_image_pipeline(const Genesys_Device& dev, const ScanSession& session,
+ unsigned pipeline_index, bool log_image_data);
+
+// sets up a image pipeline for device `dev`
+void setup_image_pipeline(Genesys_Device& dev, const ScanSession& session);
std::uint8_t compute_frontend_gain(float value, float target_value,
FrontendType frontend_type);
-template<class T>
-inline T abs_diff(T a, T b)
-{
- if (a < b) {
- return b - a;
- } else {
- return a - b;
- }
-}
-
-inline uint64_t align_multiple_floor(uint64_t x, uint64_t multiple)
-{
- return (x / multiple) * multiple;
-}
-
-inline uint64_t align_multiple_ceil(uint64_t x, uint64_t multiple)
-{
- return ((x + multiple - 1) / multiple) * multiple;
-}
-
-inline uint64_t multiply_by_depth_ceil(uint64_t pixels, uint64_t depth)
-{
- if (depth == 1) {
- return (pixels / 8) + ((pixels % 8) ? 1 : 0);
- } else {
- return pixels * (depth / 8);
- }
-}
-
-template<class T>
-inline T clamp(const T& value, const T& lo, const T& hi)
-{
- if (value < lo)
- return lo;
- if (value > hi)
- return hi;
- return value;
-}
-
/*---------------------------------------------------------------------------*/
/* ASIC specific functions declarations */
/*---------------------------------------------------------------------------*/
@@ -502,15 +444,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)
diff --git a/backend/genesys/motor.cpp b/backend/genesys/motor.cpp
index 910266a..a18d6e1 100644
--- a/backend/genesys/motor.cpp
+++ b/backend/genesys/motor.cpp
@@ -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);
@@ -120,6 +141,10 @@ MotorSlopeTable create_slope_table(const MotorSlope& slope, unsigned target_spee
dbg.log(DBG_warn, "failed to reach target speed");
}
+ if (target_speed_shifted_w >= std::numeric_limits<std::uint16_t>::max()) {
+ throw SaneException("Target motor speed is too low");
+ }
+
unsigned final_speed = std::max(target_speed_shifted_w, max_speed_shifted_w);
table.table.reserve(max_size);
@@ -130,26 +155,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 +183,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;
}
diff --git a/backend/genesys/motor.h b/backend/genesys/motor.h
index d80da6d..c433c0e 100644
--- a/backend/genesys/motor.h
+++ b/backend/genesys/motor.h
@@ -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");
+ }
+ 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 static_cast<StepType>(slopes.size() - 1);
+ return step_type;
}
};
diff --git a/backend/genesys/register.h b/backend/genesys/register.h
index bbc7ec8..51aab90 100644
--- a/backend/genesys/register.h
+++ b/backend/genesys/register.h
@@ -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);
diff --git a/backend/genesys/scanner_interface.h b/backend/genesys/scanner_interface.h
index 03c7132..70413d1 100644
--- a/backend/genesys/scanner_interface.h
+++ b/backend/genesys/scanner_interface.h
@@ -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;
diff --git a/backend/genesys/scanner_interface_usb.cpp b/backend/genesys/scanner_interface_usb.cpp
index d4d83dd..d405ede 100644
--- a/backend/genesys/scanner_interface_usb.cpp
+++ b/backend/genesys/scanner_interface_usb.cpp
@@ -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)
diff --git a/backend/genesys/scanner_interface_usb.h b/backend/genesys/scanner_interface_usb.h
index 06b51ff..33fb8fe 100644
--- a/backend/genesys/scanner_interface_usb.h
+++ b/backend/genesys/scanner_interface_usb.h
@@ -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;
diff --git a/backend/genesys/sensor.cpp b/backend/genesys/sensor.cpp
index e54af65..ce51403 100644
--- a/backend/genesys/sensor.cpp
+++ b/backend/genesys/sensor.cpp
@@ -51,10 +51,16 @@ namespace genesys {
std::ostream& operator<<(std::ostream& out, const StaggerConfig& config)
{
- out << "StaggerConfig{\n"
- << " min_resolution: " << config.min_resolution() << '\n'
- << " lines_at_min: " << config.lines_at_min() << '\n'
- << "}";
+ if (config.shifts().empty()) {
+ out << "StaggerConfig{}";
+ return out;
+ }
+
+ out << "StaggerConfig{ " << config.shifts().front();
+ for (auto it = std::next(config.shifts().begin()); it != config.shifts().end(); ++it) {
+ out << ", " << *it;
+ }
+ out << " }";
return out;
}
@@ -64,6 +70,11 @@ std::ostream& operator<<(std::ostream& out, const FrontendType& type)
case FrontendType::UNKNOWN: out << "UNKNOWN"; break;
case FrontendType::WOLFSON: out << "WOLFSON"; break;
case FrontendType::ANALOG_DEVICES: out << "ANALOG_DEVICES"; break;
+ case FrontendType::CANON_LIDE_80: out << "CANON_LIDE_80"; break;
+ case FrontendType::WOLFSON_GL841: out << "WOLFSON_GL841"; break;
+ case FrontendType::WOLFSON_GL846: out << "WOLFSON_GL846"; break;
+ case FrontendType::ANALOG_DEVICES_GL847: out << "ANALOG_DEVICES_GL847"; break;
+ case FrontendType::WOLFSON_GL124: out << "WOLFSON_GL124"; break;
default: out << "(unknown value)";
}
return out;
@@ -91,7 +102,7 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Frontend& frontend)
StreamStateSaver state_saver{out};
out << "Genesys_Frontend{\n"
- << " id: " << static_cast<unsigned>(frontend.id) << '\n'
+ << " id: " << frontend.id << '\n'
<< " regs: " << format_indent_braced_list(4, frontend.regs) << '\n'
<< std::hex
<< " reg2[0]: " << frontend.reg2[0] << '\n'
@@ -112,33 +123,23 @@ std::ostream& operator<<(std::ostream& out, const SensorExposure& exposure)
return out;
}
-std::ostream& operator<<(std::ostream& out, const ResolutionFilter& resolutions)
-{
- if (resolutions.matches_any()) {
- out << "ANY";
- return out;
- }
- out << format_vector_unsigned(4, resolutions.resolutions());
- return out;
-}
-
std::ostream& operator<<(std::ostream& out, const 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'
@@ -146,8 +147,9 @@ std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor)
<< " segment_size: " << sensor.segment_size << '\n'
<< " segment_order: "
<< format_indent_braced_list(4, format_vector_unsigned(4, sensor.segment_order)) << '\n'
- << " stagger_config: " << format_indent_braced_list(4, sensor.stagger_config) << '\n'
- << " custom_base_regs: " << format_indent_braced_list(4, sensor.custom_base_regs) << '\n'
+ << " stagger_x: " << sensor.stagger_x << '\n'
+ << " stagger_y: " << sensor.stagger_y << '\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'
diff --git a/backend/genesys/sensor.h b/backend/genesys/sensor.h
index e70728e..ca6fef7 100644
--- a/backend/genesys/sensor.h
+++ b/backend/genesys/sensor.h
@@ -47,6 +47,7 @@
#include "enums.h"
#include "register.h"
#include "serialize.h"
+#include "value_filter.h"
#include <array>
#include <functional>
@@ -72,31 +73,30 @@ class StaggerConfig
{
public:
StaggerConfig() = default;
- StaggerConfig(unsigned min_resolution, unsigned lines_at_min) :
- min_resolution_{min_resolution},
- lines_at_min_{lines_at_min}
+ explicit StaggerConfig(std::initializer_list<std::size_t> shifts) :
+ shifts_{shifts}
{
}
- unsigned stagger_at_resolution(unsigned xresolution, unsigned yresolution) const
+ std::size_t max_shift() const
{
- if (min_resolution_ == 0 || xresolution < min_resolution_)
+ if (shifts_.empty()) {
return 0;
- return yresolution / min_resolution_ * lines_at_min_;
+ }
+ return *std::max_element(shifts_.begin(), shifts_.end());
}
- unsigned min_resolution() const { return min_resolution_; }
- unsigned lines_at_min() const { return lines_at_min_; }
+ bool empty() const { return shifts_.empty(); }
+ std::size_t size() const { return shifts_.size(); }
+ const std::vector<std::size_t>& shifts() const { return shifts_; }
bool operator==(const StaggerConfig& other) const
{
- return min_resolution_ == other.min_resolution_ &&
- lines_at_min_ == other.lines_at_min_;
+ return shifts_ == other.shifts_;
}
private:
- unsigned min_resolution_ = 0;
- unsigned lines_at_min_ = 0;
+ std::vector<std::size_t> shifts_;
template<class Stream>
friend void serialize(Stream& str, StaggerConfig& x);
@@ -105,8 +105,7 @@ private:
template<class Stream>
void serialize(Stream& str, StaggerConfig& x)
{
- serialize(str, x.min_resolution_);
- serialize(str, x.lines_at_min_);
+ serialize(str, x.shifts_);
}
std::ostream& operator<<(std::ostream& out, const StaggerConfig& config);
@@ -114,9 +113,14 @@ std::ostream& operator<<(std::ostream& out, const StaggerConfig& config);
enum class FrontendType : unsigned
{
- UNKNOWN,
+ UNKNOWN = 0,
WOLFSON,
- ANALOG_DEVICES
+ ANALOG_DEVICES,
+ CANON_LIDE_80,
+ WOLFSON_GL841, // old code path, likely wrong calculation
+ WOLFSON_GL846, // old code path, likely wrong calculation
+ ANALOG_DEVICES_GL847, // old code path, likely wrong calculation
+ WOLFSON_GL124, // old code path, likely wrong calculation
};
inline void serialize(std::istream& str, FrontendType& x)
@@ -242,54 +246,6 @@ struct SensorExposure {
std::ostream& operator<<(std::ostream& out, const SensorExposure& exposure);
-class ResolutionFilter
-{
-public:
- struct Any {};
- static constexpr Any ANY{};
-
- ResolutionFilter() : matches_any_{false} {}
- ResolutionFilter(Any) : matches_any_{true} {}
- ResolutionFilter(std::initializer_list<unsigned> resolutions) :
- matches_any_{false},
- resolutions_{resolutions}
- {}
-
- bool matches(unsigned resolution) const
- {
- if (matches_any_)
- return true;
- auto it = std::find(resolutions_.begin(), resolutions_.end(), resolution);
- return it != resolutions_.end();
- }
-
- bool operator==(const ResolutionFilter& other) const
- {
- return matches_any_ == other.matches_any_ && resolutions_ == other.resolutions_;
- }
-
- bool matches_any() const { return matches_any_; }
- const std::vector<unsigned>& resolutions() const { return resolutions_; }
-
-private:
- bool matches_any_ = false;
- std::vector<unsigned> resolutions_;
-
- template<class Stream>
- friend void serialize(Stream& str, ResolutionFilter& x);
-};
-
-std::ostream& operator<<(std::ostream& out, const ResolutionFilter& resolutions);
-
-template<class Stream>
-void serialize(Stream& str, ResolutionFilter& x)
-{
- serialize(str, x.matches_any_);
- serialize_newline(str);
- serialize(str, x.resolutions_);
-}
-
-
struct Genesys_Sensor {
Genesys_Sensor() = default;
@@ -300,10 +256,15 @@ struct Genesys_Sensor {
// sensor resolution in CCD pixels. Note that we may read more than one CCD pixel per logical
// pixel, see ccd_pixels_per_system_pixel()
- unsigned optical_res = 0;
+ unsigned full_resolution = 0;
+
+ // sensor resolution in pixel values that are read by the chip. Many scanners make low
+ // resolutions faster by configuring the timings in such a way that 1/2 or 1/4 of pixel values
+ // that are read. If zero, then it is equal to `full_resolution`.
+ unsigned optical_resolution = 0;
// the resolution list that the sensor is usable at.
- ResolutionFilter resolutions = ResolutionFilter::ANY;
+ ValueFilterAny<unsigned> resolutions = VALUE_FILTER_ANY;
// the channel list that the sensor is usable at
std::vector<unsigned> channels = { 1, 3 };
@@ -313,29 +274,32 @@ struct Genesys_Sensor {
// The scanner may be setup to use a custom dpihw that does not correspond to any actual
// resolution. The value zero does not set the override.
- unsigned register_dpihw_override = 0;
-
- // The scanner may be setup to use a custom logical dpihw that does not correspond to any actual
- // resolution. The value zero does not set the override.
- unsigned logical_dpihw_override = 0;
+ unsigned register_dpihw = 0;
// The scanner may be setup to use a custom dpiset value that does not correspond to any actual
// resolution. The value zero does not set the override.
- unsigned dpiset_override = 0;
+ unsigned register_dpiset = 0;
+
+ // The resolution to use for shading calibration
+ unsigned shading_resolution = 0;
- // CCD may present itself as half or quarter-size CCD on certain resolutions
- int ccd_size_divisor = 1;
+ // How many real pixels correspond to one shading pixel that is sent to the scanner
+ unsigned shading_factor = 1;
- // Some scanners need an additional multiplier over the scan coordinates
- int pixel_count_multiplier = 1;
+ // How many pixels the shading data is offset to the right from the acquired data. Calculated
+ // in shading resolution.
+ int shading_pixel_offset = 0;
+
+ // This defines the ratio between logical pixel coordinates and the pixel coordinates sent to
+ // the scanner.
+ Ratio pixel_count_ratio = Ratio{1, 1};
+
+ // The offset in pixels in terms of scan resolution that needs to be applied to scan position.
+ int output_pixel_offset = 0;
int black_pixels = 0;
// value of the dummy register
int dummy_pixel = 0;
- // last pixel of CCD margin at optical resolution
- int ccd_start_xoffset = 0;
- // 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)
@@ -346,8 +310,7 @@ struct Genesys_Sensor {
int exposure_lperiod = -1;
- // the number of pixels in a single segment.
- // only on gl843
+ // the number of pixels in a single segment. This is counted in output resolution.
unsigned segment_size = 0;
// the order of the segments, if any, for the sensor. If the sensor is not segmented or uses
@@ -355,31 +318,28 @@ struct Genesys_Sensor {
// only on gl843
std::vector<unsigned> segment_order;
- // some CCDs use two arrays of pixels for double resolution. On such CCDs when scanning at
- // high-enough resolution, every other pixel column is shifted
- StaggerConfig stagger_config;
+ // some CCDs use multiple arrays of pixels for double or quadruple resolution. This can result
+ // in the following effects on the output:
+ // - every n-th column may be shifted in a vertical direction.
+ // - the columns themselves may be reordered in arbitrary order and may require shifting
+ // in X direction.
+ StaggerConfig stagger_x;
+ StaggerConfig stagger_y;
+
+ // True if calibration should be performed on host-side
+ bool use_host_side_calib = false;
- GenesysRegisterSettingSet custom_base_regs; // gl646-specific
GenesysRegisterSettingSet custom_regs;
GenesysRegisterSettingSet custom_fe_regs;
// red, green and blue gamma coefficient for default gamma tables
AssignableArray<float, 3> gamma;
- std::function<unsigned(const Genesys_Sensor&, unsigned)> get_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
- {
- return get_ccd_size_divisor_fun(*this, xres);
- }
- unsigned get_hwdpi_divisor_for_dpi(unsigned xres) const
+ unsigned get_optical_resolution() 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,22 +365,26 @@ struct Genesys_Sensor {
bool operator==(const Genesys_Sensor& other) const
{
return sensor_id == other.sensor_id &&
- optical_res == other.optical_res &&
+ full_resolution == other.full_resolution &&
+ optical_resolution == other.optical_resolution &&
resolutions == other.resolutions &&
method == other.method &&
- ccd_size_divisor == other.ccd_size_divisor &&
+ shading_resolution == other.shading_resolution &&
+ shading_factor == other.shading_factor &&
+ shading_pixel_offset == other.shading_pixel_offset &&
+ pixel_count_ratio == other.pixel_count_ratio &&
+ output_pixel_offset == other.output_pixel_offset &&
black_pixels == other.black_pixels &&
dummy_pixel == other.dummy_pixel &&
- ccd_start_xoffset == other.ccd_start_xoffset &&
- sensor_pixels == other.sensor_pixels &&
fau_gain_white_ref == other.fau_gain_white_ref &&
gain_white_ref == other.gain_white_ref &&
exposure == other.exposure &&
exposure_lperiod == other.exposure_lperiod &&
segment_size == other.segment_size &&
segment_order == other.segment_order &&
- stagger_config == other.stagger_config &&
- custom_base_regs == other.custom_base_regs &&
+ stagger_x == other.stagger_x &&
+ stagger_y == other.stagger_y &&
+ 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 +395,16 @@ template<class Stream>
void serialize(Stream& str, Genesys_Sensor& x)
{
serialize(str, x.sensor_id);
- serialize(str, x.optical_res);
+ serialize(str, x.full_resolution);
serialize(str, x.resolutions);
serialize(str, x.method);
- serialize(str, x.ccd_size_divisor);
+ serialize(str, x.shading_resolution);
+ serialize(str, x.shading_factor);
+ serialize(str, x.shading_pixel_offset);
+ serialize(str, x.output_pixel_offset);
+ serialize(str, x.pixel_count_ratio);
serialize(str, x.black_pixels);
serialize(str, x.dummy_pixel);
- serialize(str, x.ccd_start_xoffset);
- serialize(str, x.sensor_pixels);
serialize(str, x.fau_gain_white_ref);
serialize(str, x.gain_white_ref);
serialize_newline(str);
@@ -451,9 +417,11 @@ void serialize(Stream& str, Genesys_Sensor& x)
serialize_newline(str);
serialize(str, x.segment_order);
serialize_newline(str);
- serialize(str, x.stagger_config);
+ serialize(str, x.stagger_x);
+ serialize_newline(str);
+ serialize(str, x.stagger_y);
serialize_newline(str);
- serialize(str, x.custom_base_regs);
+ serialize(str, x.use_host_side_calib);
serialize_newline(str);
serialize(str, x.custom_regs);
serialize_newline(str);
diff --git a/backend/genesys/settings.cpp b/backend/genesys/settings.cpp
index 41c66de..c2b54dc 100644
--- a/backend/genesys/settings.cpp
+++ b/backend/genesys/settings.cpp
@@ -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 &&
+ stagger_x == other.stagger_x &&
+ stagger_y == other.stagger_y &&
+ segment_count == other.segment_count &&
+ pixel_startx == other.pixel_startx &&
+ pixel_endx == other.pixel_endx &&
+ pixel_count_ratio == other.pixel_count_ratio &&
+ conseq_pixel_dist == other.conseq_pixel_dist &&
+ output_segment_pixel_group_count == other.output_segment_pixel_group_count &&
+ output_segment_start_offset == other.output_segment_start_offset &&
+ shading_pixel_offset == other.shading_pixel_offset &&
+ buffer_size_read == other.buffer_size_read &&
+ enable_ledadd == other.enable_ledadd &&
+ use_host_side_calib == other.use_host_side_calib;
+}
+
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'
@@ -107,20 +153,19 @@ std::ostream& operator<<(std::ostream& out, const ScanSession& session)
<< " color_shift_lines_b: " << session.color_shift_lines_b << '\n'
<< " max_color_shift_lines: " << session.max_color_shift_lines << '\n'
<< " enable_ledadd: " << session.enable_ledadd << '\n'
+ << " stagger_x: " << session.stagger_x << '\n'
+ << " stagger_y: " << session.stagger_y << '\n'
<< " segment_count: " << session.segment_count << '\n'
<< " pixel_startx: " << session.pixel_startx << '\n'
<< " pixel_endx: " << session.pixel_endx << '\n'
+ << " pixel_count_ratio: " << session.pixel_count_ratio << '\n'
<< " conseq_pixel_dist: " << session.conseq_pixel_dist << '\n'
<< " output_segment_pixel_group_count: "
<< session.output_segment_pixel_group_count << '\n'
+ << " shading_pixel_offset: " << session.shading_pixel_offset << '\n'
<< " buffer_size_read: " << session.buffer_size_read << '\n'
- << " buffer_size_read: " << session.buffer_size_lines << '\n'
- << " buffer_size_shrink: " << session.buffer_size_shrink << '\n'
- << " buffer_size_out: " << session.buffer_size_out << '\n'
- << " filters: "
- << (session.pipeline_needs_reorder ? " reorder": "")
- << (session.pipeline_needs_ccd ? " ccd": "")
- << (session.pipeline_needs_shrink ? " shrink": "") << '\n'
+ << " enable_ledadd: " << session.enable_ledadd << '\n'
+ << " use_host_side_calib: " << session.use_host_side_calib << '\n'
<< " params: " << format_indent_braced_list(4, session.params) << '\n'
<< "}";
return out;
diff --git a/backend/genesys/settings.h b/backend/genesys/settings.h
index a697e60..f78845b 100644
--- a/backend/genesys/settings.h
+++ b/backend/genesys/settings.h
@@ -46,6 +46,8 @@
#include "enums.h"
#include "serialize.h"
+#include "utilities.h"
+#include "sensor.h"
namespace genesys {
@@ -60,9 +62,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;
@@ -79,15 +81,6 @@ struct Genesys_Settings
// true if scan is true gray, false if monochrome scan
int true_gray = 0;
- // lineart threshold
- int threshold = 0;
-
- // lineart threshold curve for dynamic rasterization
- int threshold_curve = 0;
-
- // Disable interpolation for xres<yres
- int disable_interpolation = 0;
-
// value for contrast enhancement in the [-100..100] range
int contrast = 0;
@@ -116,12 +109,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
@@ -144,7 +138,7 @@ struct SetupParams {
ColorFilter color_filter = static_cast<ColorFilter>(NOT_SET);
- ScanFlag flags;
+ ScanFlag flags = ScanFlag::NONE;
unsigned get_requested_pixels() const
{
@@ -210,15 +204,10 @@ struct ScanSession {
// whether the session setup has been computed via compute_session()
bool computed = false;
- // specifies the reduction (if any) of hardware dpi on the Genesys chip side.
- // except gl646
- unsigned hwdpi_divisor = 1;
-
- // specifies the 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;
+ // specifies the full resolution of the sensor that is being used.
+ unsigned full_resolution = 0;
- // 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 +217,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;
@@ -259,7 +253,7 @@ struct ScanSession {
unsigned output_total_bytes = 0;
// the number of staggered lines (i.e. lines that overlap during scanning due to line being
- // thinner than the CCD element)
+ // thinner than the CCD element). Computed according to stagger_y.
unsigned num_staggered_lines = 0;
// the number of lines that color channels shift due to different physical positions of
@@ -273,6 +267,11 @@ struct ScanSession {
// actual line shift of the blue color
unsigned color_shift_lines_b = 0;
+ // The shifts that need to be applied to the output pixels in x direction.
+ StaggerConfig stagger_x;
+ // The shifts that need to be applied to the output pixels in y direction.
+ StaggerConfig stagger_y;
+
// the number of scanner segments used in the current scan
unsigned segment_count = 1;
@@ -280,8 +279,18 @@ struct ScanSession {
unsigned pixel_startx = 0;
unsigned pixel_endx = 0;
- // certain scanners require the logical pixel count to be multiplied on certain resolutions
- unsigned pixel_count_multiplier = 1;
+ /* The following defines the ratio between logical pixel count and pixel count setting sent to
+ the scanner. The ratio is affected by the following:
+
+ - Certain scanners just like to multiply the pixel number by a multiplier that depends on
+ the resolution.
+
+ - The sensor may be configured to output one value per multiple physical pixels
+
+ - The scanner will automatically average the pixels that come from the sensor using a
+ certain ratio.
+ */
+ Ratio pixel_count_ratio = Ratio{1, 1};
// Distance in pixels between consecutive pixels, e.g. between odd and even pixels. Note that
// the number of segments can be large.
@@ -297,19 +306,18 @@ struct ScanSession {
// Currently it's always zero.
unsigned output_segment_start_offset = 0;
- // the sizes of the corresponding buffers
+ // How many pixels the shading data is offset to the right from the acquired data. Calculated
+ // in shading resolution.
+ int shading_pixel_offset = 0;
+
+ // the size of the read buffer.
size_t buffer_size_read = 0;
- 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;
- // what pipeline modifications are needed
- bool pipeline_needs_reorder = false;
- bool pipeline_needs_ccd = false;
- bool pipeline_needs_shrink = false;
+ // whether calibration should be performed host-side
+ bool use_host_side_calib = false;
void assert_computed() const
{
@@ -317,10 +325,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.stagger_x);
+ serialize(str, x.stagger_y);
+ serialize(str, x.segment_count);
+ serialize(str, x.pixel_startx);
+ serialize(str, x.pixel_endx);
+ serialize(str, x.pixel_count_ratio);
+ serialize(str, x.conseq_pixel_dist);
+ serialize(str, x.output_segment_pixel_group_count);
+ serialize(str, x.output_segment_start_offset);
+ serialize(str, x.shading_pixel_offset);
+ serialize(str, x.buffer_size_read);
+ serialize(str, x.enable_ledadd);
+ serialize(str, x.use_host_side_calib);
+}
+
std::ostream& operator<<(std::ostream& out, const SANE_Parameters& params);
} // namespace genesys
diff --git a/backend/genesys/tables_frontend.cpp b/backend/genesys/tables_frontend.cpp
index 1edf32f..5eb6e3c 100644
--- a/backend/genesys/tables_frontend.cpp
+++ b/backend/genesys/tables_frontend.cpp
@@ -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 },
@@ -218,6 +220,30 @@ void genesys_init_frontend_tables()
fe = Genesys_Frontend();
+ fe.id = AdcId::CANON_LIDE_90;
+ fe.layout = wolfson_layout;
+ fe.layout.type = FrontendType::WOLFSON;
+ fe.regs = {
+ { 0x01, 0x23 },
+ { 0x02, 0x07 },
+ { 0x03, 0x29 },
+ { 0x06, 0x0d },
+ { 0x08, 0x00 },
+ { 0x09, 0x16 },
+ { 0x20, 0x4d },
+ { 0x21, 0x4d },
+ { 0x22, 0x4d },
+ { 0x23, 0x4d },
+ { 0x28, 0x14 },
+ { 0x29, 0x14 },
+ { 0x2a, 0x14 },
+ { 0x2b, 0x14 },
+ };
+ fe.reg2 = {0x00, 0x00, 0x00};
+ s_frontends->push_back(fe);
+
+
+ fe = Genesys_Frontend();
fe.id = AdcId::AD_XP200;
fe.layout = wolfson_layout;
fe.regs = {
@@ -242,6 +268,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 +313,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 +335,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 +414,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 +441,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 },
@@ -464,6 +484,23 @@ void genesys_init_frontend_tables()
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;
fe.regs = {
@@ -498,6 +535,23 @@ void genesys_init_frontend_tables()
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;
fe.regs = {
@@ -515,6 +569,23 @@ void genesys_init_frontend_tables()
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;
fe.regs = {
@@ -537,6 +608,26 @@ void genesys_init_frontend_tables()
fe = Genesys_Frontend();
+ fe.id = AdcId::CANON_5600F;
+ fe.layout = wolfson_layout;
+ fe.regs = {
+ { 0x01, 0x23 },
+ { 0x02, 0x24 },
+ { 0x03, 0x2f },
+ { 0x06, 0x00 },
+ { 0x08, 0x00 },
+ { 0x09, 0x00 },
+ { 0x20, 0x60 },
+ { 0x21, 0x60 },
+ { 0x22, 0x60 },
+ { 0x28, 0x77 },
+ { 0x29, 0x77 },
+ { 0x2a, 0x77 },
+ };
+ s_frontends->push_back(fe);
+
+
+ fe = Genesys_Frontend();
fe.id = AdcId::CANON_8400F;
fe.layout = wolfson_layout;
fe.regs = {
@@ -583,6 +674,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 +697,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 +724,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 },
diff --git a/backend/genesys/tables_gpo.cpp b/backend/genesys/tables_gpo.cpp
index 2c9ad5e..5c1c54f 100644
--- a/backend/genesys/tables_gpo.cpp
+++ b/backend/genesys/tables_gpo.cpp
@@ -131,6 +131,18 @@ void genesys_init_gpo_tables()
gpo = Genesys_Gpo();
+ gpo.id = GpioId::CANON_LIDE_90;
+ gpo.regs = {
+ { 0x6b, 0x03 },
+ { 0x6c, 0x74 },
+ { 0x6d, 0x80 },
+ { 0x6e, 0x7f },
+ { 0x6f, 0xe0 },
+ };
+ s_gpo->push_back(gpo);
+
+
+ gpo = Genesys_Gpo();
gpo.id = GpioId::XP200;
gpo.regs = {
{ 0x66, 0x30 },
@@ -188,10 +200,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 +216,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);
@@ -293,6 +315,19 @@ void genesys_init_gpo_tables()
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 = {
{ 0x6c, 0x4c },
@@ -320,6 +355,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 +379,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 = {
@@ -350,6 +405,22 @@ void genesys_init_gpo_tables()
gpo = Genesys_Gpo();
+ gpo.id = GpioId::CANON_5600F;
+ gpo.regs = {
+ { 0x6b, 0x87 },
+ { 0x6c, 0xf0 },
+ { 0x6d, 0x5f },
+ { 0x6e, 0x7f },
+ { 0x6f, 0xa0 },
+ { 0xa6, 0x07 },
+ { 0xa7, 0x1c },
+ { 0xa8, 0x00 },
+ { 0xa9, 0x04 },
+ };
+ s_gpo->push_back(gpo);
+
+
+ gpo = Genesys_Gpo();
gpo.id = GpioId::CANON_8400F;
gpo.regs = {
{ 0x6c, 0x9a },
@@ -382,10 +453,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 +462,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);
diff --git a/backend/genesys/tables_memory_layout.cpp b/backend/genesys/tables_memory_layout.cpp
new file mode 100644
index 0000000..3eaedd4
--- /dev/null
+++ b/backend/genesys/tables_memory_layout.cpp
@@ -0,0 +1,164 @@
+/* sane - Scanner Access Now Easy.
+
+ Copyright (C) 2020 Povilas Kanapickas <povilas@radix.lt>
+
+ This file is part of the SANE package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+*/
+
+#define DEBUG_DECLARE_ONLY
+
+#include "low.h"
+
+namespace genesys {
+
+StaticInit<std::vector<MemoryLayout>> s_memory_layout;
+
+void genesys_init_memory_layout_tables()
+{
+ s_memory_layout.init();
+
+ MemoryLayout ml;
+ ml.models = { ModelId::CANON_IMAGE_FORMULA_101 };
+ // FIXME: this scanner does not set all required registers
+ ml.regs = {
+ { 0xe0, 0x00 }, { 0xe1, 0xb0 }, { 0xe2, 0x05 }, { 0xe3, 0xe7 },
+ { 0xe4, 0x05 }, { 0xe5, 0xe8 }, { 0xe6, 0x0b }, { 0xe7, 0x1f },
+ { 0xe8, 0x0b }, { 0xe9, 0x20 },
+ };
+ s_memory_layout->push_back(ml);
+
+
+ ml = MemoryLayout();
+ ml.models = { ModelId::PLUSTEK_OPTICBOOK_3800 };
+ // FIXME: this scanner does not set all required registers
+ ml.regs = {
+ { 0xe0, 0x00 }, { 0xe1, 0x68 }, { 0xe2, 0x03 }, { 0xe3, 0x00 },
+ { 0xe4, 0x03 }, { 0xe5, 0x01 }, { 0xe6, 0x05 }, { 0xe7, 0x99 },
+ { 0xe8, 0x05 }, { 0xe9, 0x9a },
+ };
+ s_memory_layout->push_back(ml);
+
+ ml = MemoryLayout();
+ ml.models = { ModelId::PLUSTEK_OPTICFILM_7400, ModelId::PLUSTEK_OPTICFILM_8200I };
+ ml.regs = {
+ { 0x81, 0x6d }, { 0x82, 0x00 }, { 0x83, 0x00 }, { 0x84, 0x00 },
+ { 0x85, 0x00 }, { 0x86, 0x00 },
+ { 0xd0, 0x0a }, { 0xd1, 0x0a }, { 0xd2, 0x0a },
+ { 0xe0, 0x00 }, { 0xe1, 0x68 }, { 0xe2, 0x03 }, { 0xe3, 0x00 },
+ { 0xe4, 0x03 }, { 0xe5, 0x01 }, { 0xe6, 0x05 }, { 0xe7, 0x99 },
+ { 0xe8, 0x05 }, { 0xe9, 0x9a }, { 0xea, 0x08 }, { 0xeb, 0x32 },
+ { 0xec, 0x08 }, { 0xed, 0x33 }, { 0xee, 0x0a }, { 0xef, 0xcb },
+ { 0xf0, 0x0a }, { 0xf1, 0xcc }, { 0xf2, 0x0d }, { 0xf3, 0x64 },
+ { 0xf4, 0x0d }, { 0xf5, 0x65 }, { 0xf6, 0x0f }, { 0xf7, 0xfd },
+ };
+ s_memory_layout->push_back(ml);
+
+
+ /* On GL847 and GL124, the values of the base address for shading data must be multiplied by
+ 8192=0x4000 to give address on AHB
+
+ On GL847 and GL124, the values of the base address for scanned data must be multiplied by
+ 1024*2=0x0800 to give address on AHB
+ */
+ ml = MemoryLayout();
+ ml.models = { ModelId::CANON_5600F };
+ ml.regs = {
+ { 0xd0, 0x0a },
+ { 0xe0, 0x01 }, { 0xe1, 0x2c }, { 0xe2, 0x06 }, { 0xe3, 0x4e },
+ { 0xe4, 0x06 }, { 0xe5, 0x4f }, { 0xe6, 0x0b }, { 0xe7, 0x71 },
+ { 0xe8, 0x0b }, { 0xe9, 0x72 }, { 0xea, 0x10 }, { 0xeb, 0x94 },
+ { 0xec, 0x10 }, { 0xed, 0x95 }, { 0xee, 0x15 }, { 0xef, 0xb7 },
+ { 0xf0, 0x15 }, { 0xf1, 0xb8 }, { 0xf2, 0x1a }, { 0xf3, 0xda },
+ { 0xf4, 0x1a }, { 0xf5, 0xdb }, { 0xf6, 0x1f }, { 0xf7, 0xfd },
+ { 0xf8, 0x05 }
+ };
+ s_memory_layout->push_back(ml);
+
+
+ ml = MemoryLayout();
+ ml.models = { ModelId::CANON_LIDE_100 };
+ ml.regs = {
+ { 0xd0, 0x0a }, { 0xd1, 0x15 }, { 0xd2, 0x20 },
+ { 0xe0, 0x00 }, { 0xe1, 0xac }, { 0xe2, 0x02 }, { 0xe3, 0x55 },
+ { 0xe4, 0x02 }, { 0xe5, 0x56 }, { 0xe6, 0x03 }, { 0xe7, 0xff },
+ { 0xe8, 0x00 }, { 0xe9, 0xac }, { 0xea, 0x02 }, { 0xeb, 0x55 },
+ { 0xec, 0x02 }, { 0xed, 0x56 }, { 0xee, 0x03 }, { 0xef, 0xff },
+ { 0xf0, 0x00 }, { 0xf1, 0xac }, { 0xf2, 0x02 }, { 0xf3, 0x55 },
+ { 0xf4, 0x02 }, { 0xf5, 0x56 }, { 0xf6, 0x03 }, { 0xf7, 0xff },
+ };
+ s_memory_layout->push_back(ml);
+
+
+ ml = MemoryLayout();
+ ml.models = { ModelId::CANON_LIDE_200 };
+ ml.regs = {
+ { 0xd0, 0x0a }, { 0xd1, 0x1f }, { 0xd2, 0x34 },
+ { 0xe0, 0x01 }, { 0xe1, 0x24 }, { 0xe2, 0x02 }, { 0xe3, 0x91 },
+ { 0xe4, 0x02 }, { 0xe5, 0x92 }, { 0xe6, 0x03 }, { 0xe7, 0xff },
+ { 0xe8, 0x01 }, { 0xe9, 0x24 }, { 0xea, 0x02 }, { 0xeb, 0x91 },
+ { 0xec, 0x02 }, { 0xed, 0x92 }, { 0xee, 0x03 }, { 0xef, 0xff },
+ { 0xf0, 0x01 }, { 0xf1, 0x24 }, { 0xf2, 0x02 }, { 0xf3, 0x91 },
+ { 0xf4, 0x02 }, { 0xf5, 0x92 }, { 0xf6, 0x03 }, { 0xf7, 0xff },
+ };
+ s_memory_layout->push_back(ml);
+
+
+ ml = MemoryLayout();
+ ml.models = { ModelId::CANON_LIDE_700F };
+ ml.regs = {
+ { 0xd0, 0x0a }, { 0xd1, 0x33 }, { 0xd2, 0x5c },
+ { 0xe0, 0x02 }, { 0xe1, 0x14 }, { 0xe2, 0x09 }, { 0xe3, 0x09 },
+ { 0xe4, 0x09 }, { 0xe5, 0x0a }, { 0xe6, 0x0f }, { 0xe7, 0xff },
+ { 0xe8, 0x02 }, { 0xe9, 0x14 }, { 0xea, 0x09 }, { 0xeb, 0x09 },
+ { 0xec, 0x09 }, { 0xed, 0x0a }, { 0xee, 0x0f }, { 0xef, 0xff },
+ { 0xf0, 0x02 }, { 0xf1, 0x14 }, { 0xf2, 0x09 }, { 0xf3, 0x09 },
+ { 0xf4, 0x09 }, { 0xf5, 0x0a }, { 0xf6, 0x0f }, { 0xf7, 0xff },
+ };
+ s_memory_layout->push_back(ml);
+
+
+ ml = MemoryLayout();
+ ml.models = { ModelId::CANON_LIDE_110, ModelId::CANON_LIDE_120 };
+ ml.regs = {
+ { 0xd0, 0x0a }, { 0xd1, 0x15 }, { 0xd2, 0x20 },
+ { 0xe0, 0x00 }, { 0xe1, 0xac }, { 0xe2, 0x08 }, { 0xe3, 0x55 },
+ { 0xe4, 0x08 }, { 0xe5, 0x56 }, { 0xe6, 0x0f }, { 0xe7, 0xff },
+ { 0xe8, 0x00 }, { 0xe9, 0xac }, { 0xea, 0x08 }, { 0xeb, 0x55 },
+ { 0xec, 0x08 }, { 0xed, 0x56 }, { 0xee, 0x0f }, { 0xef, 0xff },
+ { 0xf0, 0x00 }, { 0xf1, 0xac }, { 0xf2, 0x08 }, { 0xf3, 0x55 },
+ { 0xf4, 0x08 }, { 0xf5, 0x56 }, { 0xf6, 0x0f }, { 0xf7, 0xff },
+
+ };
+ s_memory_layout->push_back(ml);
+
+
+ ml = MemoryLayout();
+ ml.models = { ModelId::CANON_LIDE_210, ModelId::CANON_LIDE_220 };
+ ml.regs = {
+ { 0xd0, 0x0a }, { 0xd1, 0x1f }, { 0xd2, 0x34 },
+ { 0xe0, 0x01 }, { 0xe1, 0x24 }, { 0xe2, 0x08 }, { 0xe3, 0x91 },
+ { 0xe4, 0x08 }, { 0xe5, 0x92 }, { 0xe6, 0x0f }, { 0xe7, 0xff },
+ { 0xe8, 0x01 }, { 0xe9, 0x24 }, { 0xea, 0x08 }, { 0xeb, 0x91 },
+ { 0xec, 0x08 }, { 0xed, 0x92 }, { 0xee, 0x0f }, { 0xef, 0xff },
+ { 0xf0, 0x01 }, { 0xf1, 0x24 }, { 0xf2, 0x08 }, { 0xf3, 0x91 },
+ { 0xf4, 0x08 }, { 0xf5, 0x92 }, { 0xf6, 0x0f }, { 0xf7, 0xff },
+ };
+ s_memory_layout->push_back(ml);
+}
+
+} // namespace genesys
diff --git a/backend/genesys/tables_model.cpp b/backend/genesys/tables_model.cpp
index 0b3a0af..2c5e6a3 100644
--- a/backend/genesys/tables_model.cpp
+++ b/backend/genesys/tables_model.cpp
@@ -58,10 +58,44 @@
namespace genesys {
-StaticInit<std::vector<Genesys_USB_Device_Entry>> s_usb_devices;
+StaticInit<std::vector<UsbDeviceEntry>> s_usb_devices;
void genesys_init_usb_device_tables()
{
+ /* Guidelines on calibration area sizes
+ ------------------------------------
+
+ on many scanners scanning a single line takes aroung 10ms. In order not to take excessive
+ amount of time, the sizes of the calibration area are limited as follows:
+ 2400 dpi or less: 4mm (would take ~4 seconds on 2400 dpi)
+ 4800 dpi or less: 3mm (would take ~6 seconds on 4800 dpi)
+ anything more: 2mm (would take ~7 seconds on 9600 dpi)
+
+ Optional properties
+ -------------------
+
+ All fields of the Genesys_Model class are defined even if they use default value, with
+ the following exceptions:
+
+ If the scanner does not have ScanMethod::TRANSPARENCY or ScanMethod::TRANSPARENCY_INFRARED,
+ the following properties are optional:
+
+ model.x_offset_ta = 0.0;
+ model.y_offset_ta = 0.0;
+ model.x_size_ta = 0.0;
+ model.y_size_ta = 0.0;
+
+ model.y_offset_sensor_to_ta = 0.0;
+ model.y_offset_calib_white_ta = 0.0;
+ model.y_size_calib_ta_mm = 0.0;
+
+ If the scanner does not have ModelFlag::DARK_WHITE_CALIBRATION, then the following
+ properties are optional:
+
+ model.y_offset_calib_dark_white_mm = 0.0;
+ model.y_size_calib_dark_white_mm = 0.0;
+ */
+
s_usb_devices.init();
Genesys_Model model;
@@ -87,15 +121,9 @@ void genesys_init_usb_device_tables()
model.y_size = 299.0;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 1.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 228.6;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -112,10 +140,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_UMAX;
model.gpio_id = GpioId::UMAX;
model.motor_id = MotorId::UMAX;
- model.flags = GENESYS_FLAG_UNTESTED;
+ model.flags = ModelFlag::UNTESTED;
model.buttons = GENESYS_HAS_NO_BUTTONS;
- model.shading_lines = 20;
- model.shading_ta_lines = 0;
model.search_lines = 200;
s_usb_devices->emplace_back(0x0638, 0x0a10, model);
@@ -144,17 +170,13 @@ void genesys_init_usb_device_tables()
model.x_size = 218.0;
model.y_size = 299.0;
- model.y_offset_calib_white = 6.0;
+ model.y_offset_calib_white = 3.0;
+ model.y_size_calib_mm = 3.0;
+ model.y_offset_calib_dark_white_mm = 1.0;
+ model.y_size_calib_dark_white_mm = 6.0;
+ model.x_size_calib_mm = 220.13334;
model.x_offset_calib_black = 0.0;
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
-
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -170,16 +192,12 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_35;
model.gpio_id = GpioId::CANON_LIDE_35;
model.motor_id = MotorId::CANON_LIDE_35;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_WHITE_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::DARK_WHITE_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_FILE_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_COPY_SW;
- model.shading_lines = 280;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a9, 0x2213, model);
@@ -209,15 +227,9 @@ void genesys_init_usb_device_tables()
model.y_size = 300.0;
model.y_offset_calib_white = 9.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 0.0;
- model.y_size_ta = 0.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 227.584;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -234,12 +246,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::KVSS080;
model.gpio_id = GpioId::KVSS080;
model.motor_id = MotorId::KVSS080;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 100;
s_usb_devices->emplace_back(0x04da, 0x100f, model);
@@ -269,15 +277,9 @@ void genesys_init_usb_device_tables()
model.y_size = 314.5;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 226.9067;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -294,13 +296,10 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::G4050;
model.gpio_id = GpioId::G4050;
model.motor_id = MotorId::G4050;
- model.flags = GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_SHADING_REPARK |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 100;
s_usb_devices->emplace_back(0x03f0, 0x1b05, model);
@@ -329,15 +328,9 @@ void genesys_init_usb_device_tables()
model.y_size = 315.0;
model.y_offset_calib_white = 3.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 226.9067;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -353,13 +346,10 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::G4050;
model.gpio_id = GpioId::G4050;
model.motor_id = MotorId::G4050;
- model.flags = GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 100;
s_usb_devices->emplace_back(0x03f0, 0x4505, model);
@@ -389,15 +379,9 @@ void genesys_init_usb_device_tables()
model.y_size = 315.0;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 8.0;
- model.y_offset_ta = 13.00;
- model.x_size_ta = 217.9;
- model.y_size_ta = 250.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 40.0;
+ model.x_size_calib_mm = 226.9067;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -414,13 +398,10 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::G4050;
model.gpio_id = GpioId::G4050;
model.motor_id = MotorId::G4050;
- model.flags = GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 100;
s_usb_devices->emplace_back(0x03f0, 0x4605, model);
@@ -438,6 +419,10 @@ void genesys_init_usb_device_tables()
{ ScanMethod::FLATBED },
{ 1200, 600, 300 },
{ 1200, 600, 300 },
+ }, {
+ { ScanMethod::TRANSPARENCY },
+ { 4800, 2400, 1200 },
+ { 9600, 4800, 2400, 1200 },
}
};
@@ -445,20 +430,23 @@ void genesys_init_usb_device_tables()
model.bpp_color_values = { 8, 16 };
model.x_offset = 6.0;
- model.y_offset = 12.00;
+ model.y_offset = 10.00;
model.x_size = 215.9;
model.y_size = 297.0;
- model.y_offset_calib_white = 0.0;
+ model.y_offset_calib_white = 2.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
+ model.x_size_calib_mm = 241.3;
- model.x_offset_ta = 8.0;
- model.y_offset_ta = 13.00;
- model.x_size_ta = 217.9;
- model.y_size_ta = 250.0;
+ model.x_offset_ta = 115.0;
+ model.y_offset_ta = 37.0;
+ model.x_size_ta = 35.0;
+ model.y_size_ta = 230.0;
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 40.0;
+ model.y_offset_sensor_to_ta = 23.0;
+ model.y_offset_calib_white_ta = 24.0;
+ model.y_size_calib_ta_mm = 2.0;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -475,15 +463,13 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_4400F;
model.gpio_id = GpioId::CANON_4400F;
model.motor_id = MotorId::CANON_4400F;
- model.flags = GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_FULL_HWDPI_MODE |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_SHADING_REPARK;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::UTA_NO_SECONDARY_MOTOR;
+
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 100;
s_usb_devices->emplace_back(0x04a9, 0x2228, model);
@@ -515,13 +501,15 @@ void genesys_init_usb_device_tables()
model.bpp_gray_values = { 8, 16 };
model.bpp_color_values = { 8, 16 };
- model.x_offset = 3.5;
+ model.x_offset = 5.5;
model.y_offset = 17.00;
model.x_size = 219.9;
model.y_size = 300.0;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 3.0;
model.x_offset_calib_black = 10.0;
+ model.x_size_calib_mm = 225.425;
model.x_offset_ta = 75.0;
model.y_offset_ta = 45.00;
@@ -530,6 +518,7 @@ void genesys_init_usb_device_tables()
model.y_offset_sensor_to_ta = 22.0;
model.y_offset_calib_white_ta = 25.0;
+ model.y_size_calib_ta_mm = 3.0;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -546,17 +535,11 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_8400F;
model.gpio_id = GpioId::CANON_8400F;
model.motor_id = MotorId::CANON_8400F;
- model.flags = GENESYS_FLAG_HAS_UTA |
- GENESYS_FLAG_HAS_UTA_INFRARED |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_FULL_HWDPI_MODE |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_SHADING_REPARK;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::SHADING_REPARK;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW;
- model.shading_lines = 100;
- model.shading_ta_lines = 50;
model.search_lines = 100;
s_usb_devices->emplace_back(0x04a9, 0x221e, model);
@@ -590,15 +573,18 @@ void genesys_init_usb_device_tables()
model.y_size = 297.0;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 8.0;
+ model.x_size_calib_mm = 240.70734;
- model.x_offset_ta = 85.0;
- model.y_offset_ta = 26.0;
+ model.x_offset_ta = 97.0;
+ model.y_offset_ta = 38.5;
model.x_size_ta = 70.0;
model.y_size_ta = 230.0;
- model.y_offset_sensor_to_ta = 11.5;
- model.y_offset_calib_white_ta = 14.0;
+ model.y_offset_sensor_to_ta = 23.0;
+ model.y_offset_calib_white_ta = 25.5;
+ model.y_size_calib_ta_mm = 3.0;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -615,17 +601,11 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_8600F;
model.gpio_id = GpioId::CANON_8600F;
model.motor_id = MotorId::CANON_8600F;
- model.flags = GENESYS_FLAG_HAS_UTA |
- GENESYS_FLAG_HAS_UTA_INFRARED |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_FULL_HWDPI_MODE |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_SHADING_REPARK;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::SHADING_REPARK;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW;
- model.shading_lines = 50;
- model.shading_ta_lines = 50;
model.search_lines = 100;
s_usb_devices->emplace_back(0x04a9, 0x2229, model);
@@ -654,16 +634,10 @@ void genesys_init_usb_device_tables()
model.x_size = 216.07;
model.y_size = 299.0;
- model.y_offset_calib_white = 1.0;
+ model.y_offset_calib_white = 0.4233334;
+ model.y_size_calib_mm = 3.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 217.4241;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -680,18 +654,14 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_200;
model.gpio_id = GpioId::CANON_LIDE_200;
model.motor_id = MotorId::CANON_LIDE_100;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_SIS_SENSOR |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_SHADING_REPARK |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::SIS_SENSOR |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_COPY_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_FILE_SW;
- model.shading_lines = 50;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a9, 0x1904, model);
@@ -721,15 +691,9 @@ void genesys_init_usb_device_tables()
model.y_size = 300.0;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 3.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 218.7787;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -745,17 +709,13 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_110;
model.gpio_id = GpioId::CANON_LIDE_110;
model.motor_id = MotorId::CANON_LIDE_110;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_SHADING_REPARK |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_COPY_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_FILE_SW;
- model.shading_lines = 25;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a9, 0x1909, model);
@@ -785,15 +745,9 @@ void genesys_init_usb_device_tables()
model.y_size = 300.0;
model.y_offset_calib_white = 1.0;
+ model.y_size_calib_mm = 3.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 216.0694;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -808,17 +762,13 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_120;
model.gpio_id = GpioId::CANON_LIDE_120;
model.motor_id = MotorId::CANON_LIDE_120;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_SHADING_REPARK |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_COPY_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_FILE_SW;
- model.shading_lines = 50;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a9, 0x190e, model);
@@ -834,30 +784,23 @@ void genesys_init_usb_device_tables()
model.resolutions = {
{
{ ScanMethod::FLATBED },
- // BUG: 4800 resolution crashes
- { /*4800,*/ 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 },
- { /*4800,*/ 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 },
+ { 4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 },
+ { 4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 },
}
};
model.bpp_gray_values = { 8, 16 };
model.bpp_color_values = { 8, 16 };
- model.x_offset = 2.2;
+ model.x_offset = 2.1;
model.y_offset = 8.7;
model.x_size = 216.70;
model.y_size = 297.5;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 3.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 218.7787;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -874,18 +817,14 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_110;
model.gpio_id = GpioId::CANON_LIDE_210;
model.motor_id = MotorId::CANON_LIDE_210;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_SHADING_REPARK |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_COPY_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_FILE_SW |
GENESYS_HAS_EXTRA_SW;
- model.shading_lines = 60;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a9, 0x190a, model);
@@ -901,30 +840,23 @@ void genesys_init_usb_device_tables()
model.resolutions = {
{
{ ScanMethod::FLATBED },
- // BUG: 4800 resolution crashes
- { /*4800,*/ 2400, 1200, 600, 300, 150, 100, 75 },
- { /*4800,*/ 2400, 1200, 600, 300, 150, 100, 75 },
+ { 4800, 2400, 1200, 600, 300, 150, 100, 75 },
+ { 4800, 2400, 1200, 600, 300, 150, 100, 75 },
}
};
model.bpp_gray_values = { 8, 16 };
model.bpp_color_values = { 8, 16 };
- model.x_offset = 2.2;
+ model.x_offset = 2.1;
model.y_offset = 8.7;
model.x_size = 216.70;
model.y_size = 297.5;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 3.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 218.7787;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -940,84 +872,84 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_110;
model.gpio_id = GpioId::CANON_LIDE_210;
model.motor_id = MotorId::CANON_LIDE_210;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_SHADING_REPARK |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_COPY_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_FILE_SW |
GENESYS_HAS_EXTRA_SW;
- model.shading_lines = 60;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a9, 0x190f, model);
model = Genesys_Model();
- model.name = "canon-5600f";
+ model.name = "canon-canoscan-5600f";
model.vendor = "Canon";
- model.model = "5600F";
+ model.model = "CanoScan 5600F";
model.model_id = ModelId::CANON_5600F;
model.asic_type = AsicType::GL847;
model.resolutions = {
{
- { ScanMethod::FLATBED },
- { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 75 },
- { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 75 },
+ { ScanMethod::FLATBED, ScanMethod::TRANSPARENCY },
+ { 4800, 2400, 1200, 600, 300, /*150*/ },
+ { 4800, 2400, 1200, 600, 300, /*150*/ },
}
};
model.bpp_gray_values = { 8, 16 };
model.bpp_color_values = { 8, 16 };
- model.x_offset = 1.1;
- model.y_offset = 8.3;
- model.x_size = 216.07;
- model.y_size = 299.0;
+ model.x_offset = 1.5;
+ model.y_offset = 10.4;
+ model.x_size = 219.00;
+ model.y_size = 305.0;
- model.y_offset_calib_white = 3.0;
+ model.y_offset_calib_white = 2.0;
+ model.y_size_calib_mm = 2.0;
model.x_offset_calib_black = 0.0;
+ model.x_size_calib_mm = 220.5;
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
+ model.x_offset_ta = 93.0;
+ model.y_offset_ta = 42.4;
+ model.x_size_ta = 35.0;
+ model.y_size_ta = 230.0;
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.y_offset_sensor_to_ta = 0;
+ model.y_offset_calib_white_ta = 21.4;
+ model.y_size_calib_ta_mm = 1.0;
model.post_scan = 0.0;
model.eject_feed = 0.0;
model.ld_shift_r = 0;
- model.ld_shift_g = 0;
- model.ld_shift_b = 0;
+ model.ld_shift_g = 32;
+ model.ld_shift_b = 64;
model.line_mode_color_order = ColorOrder::RGB;
- model.is_cis = true;
+ model.is_cis = false;
model.is_sheetfed = false;
- model.sensor_id = SensorId::CIS_CANON_LIDE_200;
- model.adc_id = AdcId::CANON_LIDE_200;
- model.gpio_id = GpioId::CANON_LIDE_200;
- model.motor_id = MotorId::CANON_LIDE_200;
- model.flags = GENESYS_FLAG_UNTESTED |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_SIS_SENSOR |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.sensor_id = SensorId::CCD_CANON_5600F;
+ model.adc_id = AdcId::CANON_5600F;
+ model.gpio_id = GpioId::CANON_5600F;
+ model.motor_id = MotorId::CANON_5600F;
+ model.flags = ModelFlag::SIS_SENSOR |
+ ModelFlag::INVERT_PIXEL_DATA |
+ ModelFlag::DISABLE_ADC_CALIBRATION |
+ ModelFlag::DISABLE_EXPOSURE_CALIBRATION |
+ ModelFlag::HOST_SIDE_CALIBRATION_COMPLETE_SCAN |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::UTA_NO_SECONDARY_MOTOR |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_COPY_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_FILE_SW;
- model.shading_lines = 50;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a9, 0x1906, model);
@@ -1032,9 +964,10 @@ void genesys_init_usb_device_tables()
model.resolutions = {
{
+ // FIXME: support 2400 ad 4800 dpi
{ ScanMethod::FLATBED },
- { 4800, 2400, 1200, 600, 300, 200, 150, 100, 75 },
- { 4800, 2400, 1200, 600, 300, 200, 150, 100, 75 },
+ { 1200, 600, 300, 200, 150, 100, 75 },
+ { 1200, 600, 300, 200, 150, 100, 75 },
}
};
@@ -1046,16 +979,11 @@ void genesys_init_usb_device_tables()
model.x_size = 216.07;
model.y_size = 297.0;
- model.y_offset_calib_white = 1.0;
+ model.y_offset_calib_white = 0.4233334;
+ model.y_size_calib_mm = 3.0;
model.x_offset_calib_black = 0.0;
+ model.x_size_calib_mm = 219.6254;
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -1071,18 +999,14 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_700F;
model.gpio_id = GpioId::CANON_LIDE_700F;
model.motor_id = MotorId::CANON_LIDE_700;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_SIS_SENSOR |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_SHADING_REPARK |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::SIS_SENSOR |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_COPY_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_FILE_SW;
- model.shading_lines = 70;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a9, 0x1907, model);
@@ -1111,16 +1035,10 @@ void genesys_init_usb_device_tables()
model.x_size = 216.07;
model.y_size = 299.0;
- model.y_offset_calib_white = 0.0;
+ model.y_offset_calib_white = 0.4233334;
+ model.y_size_calib_mm = 3.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 217.4241;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -1136,18 +1054,14 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_200;
model.gpio_id = GpioId::CANON_LIDE_200;
model.motor_id = MotorId::CANON_LIDE_200;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_SIS_SENSOR |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_SHADING_REPARK |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::SIS_SENSOR |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_COPY_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_FILE_SW;
- model.shading_lines = 50;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a9, 0x1905, model);
@@ -1176,16 +1090,12 @@ void genesys_init_usb_device_tables()
model.x_size = 218.0;
model.y_size = 299.0;
- model.y_offset_calib_white = 6.0;
+ model.y_offset_calib_white = 3.0;
+ model.y_size_calib_mm = 3.0;
+ model.y_offset_calib_dark_white_mm = 1.0;
+ model.y_size_calib_dark_white_mm = 6.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 220.13334;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -1197,23 +1107,18 @@ void genesys_init_usb_device_tables()
model.is_cis = true;
model.is_sheetfed = false;
- model.sensor_id = SensorId::CIS_CANON_LIDE_35;
+ model.sensor_id = SensorId::CIS_CANON_LIDE_60;
model.adc_id = AdcId::CANON_LIDE_35;
model.gpio_id = GpioId::CANON_LIDE_35;
- model.motor_id = MotorId::CANON_LIDE_35;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_WHITE_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.motor_id = MotorId::CANON_LIDE_60;
+ model.flags = ModelFlag::DARK_WHITE_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW |
GENESYS_HAS_SCAN_SW |
GENESYS_HAS_FILE_SW |
GENESYS_HAS_EMAIL_SW;
- model.shading_lines = 300;
- model.shading_ta_lines = 0;
model.search_lines = 400;
- // this is completely untested
s_usb_devices->emplace_back(0x04a9, 0x221c, model);
@@ -1240,15 +1145,11 @@ void genesys_init_usb_device_tables()
model.y_size = 299.0;
model.y_offset_calib_white = 4.5;
+ model.y_size_calib_mm = 3.0;
+ model.y_offset_calib_dark_white_mm = 1.0;
+ model.y_size_calib_dark_white_mm = 6.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 216.7467;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -1265,22 +1166,77 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_80;
model.gpio_id = GpioId::CANON_LIDE_80;
model.motor_id = MotorId::CANON_LIDE_80;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_WHITE_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::DARK_WHITE_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_FILE_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_COPY_SW;
- model.shading_lines = 160;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a9, 0x2214, model);
model = Genesys_Model();
+ model.name = "canon-lide-90";
+ model.vendor = "Canon";
+ model.model = "LiDE 90";
+ model.model_id = ModelId::CANON_LIDE_90;
+ model.asic_type = AsicType::GL842;
+
+ model.resolutions = {
+ {
+ { ScanMethod::FLATBED },
+ { 2400, 1200, 600, 300 },
+ { 2400, 1200, 600, 300 },
+ }
+ };
+
+ model.bpp_gray_values = { 8, 16 };
+ model.bpp_color_values = { 8, 16 };
+ model.x_offset = 3.50;
+ model.y_offset = 9.0;
+ model.x_size = 219.0;
+ model.y_size = 299.0;
+
+ model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 2.0;
+ model.y_offset_calib_dark_white_mm = 0.0;
+ model.y_size_calib_dark_white_mm = 0.0;
+ model.x_offset_calib_black = 0.0;
+ model.x_size_calib_mm = 221.5;
+
+ model.post_scan = 0.0;
+ model.eject_feed = 0.0;
+
+ model.ld_shift_r = 0;
+ model.ld_shift_g = 0;
+ model.ld_shift_b = 0;
+
+ model.line_mode_color_order = ColorOrder::RGB;
+
+ model.is_cis = true;
+ model.is_sheetfed = false;
+ model.sensor_id = SensorId::CIS_CANON_LIDE_90;
+ model.adc_id = AdcId::CANON_LIDE_90;
+ model.gpio_id = GpioId::CANON_LIDE_90;
+ model.motor_id = MotorId::CANON_LIDE_90;
+ model.flags = ModelFlag::DISABLE_ADC_CALIBRATION |
+ ModelFlag::HOST_SIDE_CALIBRATION_COMPLETE_SCAN |
+ ModelFlag::USE_CONSTANT_FOR_DARK_CALIBRATION |
+ ModelFlag::DISABLE_FAST_FEEDING |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::CUSTOM_GAMMA;
+ model.buttons = GENESYS_HAS_SCAN_SW |
+ GENESYS_HAS_FILE_SW |
+ GENESYS_HAS_EMAIL_SW |
+ GENESYS_HAS_COPY_SW;
+ model.search_lines = 400;
+
+ s_usb_devices->emplace_back(0x04a9, 0x1900, model);
+
+
+ model = Genesys_Model();
model.name = "hewlett-packard-scanjet-2300c";
model.vendor = "Hewlett Packard";
model.model = "ScanJet 2300c";
@@ -1298,27 +1254,21 @@ void genesys_init_usb_device_tables()
model.bpp_gray_values = { 8, 16 };
model.bpp_color_values = { 8, 16 };
- model.x_offset = 2.0;
- model.y_offset = 7.5;
+ model.x_offset = 6.5;
+ model.y_offset = 8;
model.x_size = 215.9;
model.y_size = 295.0;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 1.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 227.2454;
model.post_scan = 0.0;
model.eject_feed = 0.0;
- model.ld_shift_r = 16;
- model.ld_shift_g = 8;
+ model.ld_shift_r = 32;
+ model.ld_shift_g = 16;
model.ld_shift_b = 0;
model.line_mode_color_order = ColorOrder::RGB;
@@ -1328,15 +1278,10 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_HP2300;
model.gpio_id = GpioId::HP2300;
model.motor_id = MotorId::HP2300;
- model.flags = GENESYS_FLAG_14BIT_GAMMA |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_SEARCH_START |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::GAMMA_14BIT |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW;
- model.shading_lines = 40;
- model.shading_ta_lines = 0;
model.search_lines = 132;
s_usb_devices->emplace_back(0x03f0, 0x0901, model);
@@ -1366,15 +1311,9 @@ void genesys_init_usb_device_tables()
model.y_size = 297.2;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 2.0; // FIXME: check if white area is really so small
model.x_offset_calib_black = 1.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 230.1241;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -1391,14 +1330,10 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_HP2400;
model.gpio_id = GpioId::HP2400;
model.motor_id = MotorId::HP2400;
- model.flags = GENESYS_FLAG_14BIT_GAMMA |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::GAMMA_14BIT |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW;
- model.shading_lines = 20;
- model.shading_ta_lines = 0;
model.search_lines = 132;
s_usb_devices->emplace_back(0x03f0, 0x0a01, model);
@@ -1428,15 +1363,9 @@ void genesys_init_usb_device_tables()
model.y_size = 297.2;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 220.1334;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -1453,14 +1382,10 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::AD_XP200;
model.gpio_id = GpioId::XP200;
model.motor_id = MotorId::XP200;
- model.flags = GENESYS_FLAG_14BIT_GAMMA |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION;
+ model.flags = ModelFlag::GAMMA_14BIT |
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
- model.shading_lines = 120;
- model.shading_ta_lines = 0;
model.search_lines = 132;
s_usb_devices->emplace_back(0x04a7, 0x0426, model);
@@ -1490,15 +1415,9 @@ void genesys_init_usb_device_tables()
model.y_size = 300.0;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 1.0;
-
- model.x_offset_ta = 104.0;
- model.y_offset_ta = 55.6;
- model.x_size_ta = 25.6;
- model.y_size_ta = 78.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 76.0;
+ model.x_size_calib_mm = 230.1241;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -1515,14 +1434,11 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_HP3670;
model.gpio_id = GpioId::HP3670;
model.motor_id = MotorId::HP3670;
- model.flags = GENESYS_FLAG_14BIT_GAMMA |
- GENESYS_FLAG_XPA |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::GAMMA_14BIT |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW;
- model.shading_lines = 20;
- model.shading_ta_lines = 0;
model.search_lines = 200;
s_usb_devices->emplace_back(0x03f0, 0x1405, model);
@@ -1552,15 +1468,9 @@ void genesys_init_usb_device_tables()
model.y_size = 299.0;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 1.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 229.2774;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -1577,10 +1487,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_ST12;
model.gpio_id = GpioId::ST12;
model.motor_id = MotorId::UMAX;
- model.flags = GENESYS_FLAG_UNTESTED | GENESYS_FLAG_14BIT_GAMMA;
+ model.flags = ModelFlag::UNTESTED | ModelFlag::GAMMA_14BIT;
model.buttons = GENESYS_HAS_NO_BUTTONS;
- model.shading_lines = 20;
- model.shading_ta_lines = 0;
model.search_lines = 200;
s_usb_devices->emplace_back(0x07b3, 0x0600, model);
@@ -1604,20 +1512,14 @@ void genesys_init_usb_device_tables()
model.bpp_color_values = { 8, 16 };
model.x_offset = 3.5;
- model.y_offset = 7.5;
+ model.y_offset = 7.5; // FIXME: incorrect, needs updating
model.x_size = 218.0;
model.y_size = 299.0;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 1.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 228.6;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -1634,14 +1536,10 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_ST24;
model.gpio_id = GpioId::ST24;
model.motor_id = MotorId::ST24;
- model.flags = GENESYS_FLAG_UNTESTED |
- GENESYS_FLAG_14BIT_GAMMA |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_SEARCH_START |
- GENESYS_FLAG_OFFSET_CALIBRATION;
+ model.flags = ModelFlag::UNTESTED |
+ ModelFlag::GAMMA_14BIT |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_NO_BUTTONS;
- model.shading_lines = 20;
- model.shading_ta_lines = 0;
model.search_lines = 200;
s_usb_devices->emplace_back(0x07b3, 0x0601, model);
@@ -1665,26 +1563,20 @@ void genesys_init_usb_device_tables()
model.bpp_color_values = { 8, 16 };
model.x_offset = 0.30;
- model.y_offset = 0.80;
+ model.y_offset = 4.0; // FIXME: incorrect, needs updating
model.x_size = 220.0;
model.y_size = 296.4;
model.y_offset_calib_white = 0.00;
+ model.y_size_calib_mm = 2.0;
model.x_offset_calib_black = 0.00;
-
- model.x_offset_ta = 0.00;
- model.y_offset_ta = 0.00;
- model.x_size_ta = 0.00;
- model.y_size_ta = 0.00;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.00;
+ model.x_size_calib_mm = 230.1241;
model.post_scan = 0.0;
model.eject_feed = 0.0;
- model.ld_shift_r = 48;
- model.ld_shift_g = 24;
+ model.ld_shift_r = 96;
+ model.ld_shift_g = 48;
model.ld_shift_b = 0;
model.line_mode_color_order = ColorOrder::RGB;
@@ -1694,19 +1586,15 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_5345;
model.gpio_id = GpioId::MD_5345;
model.motor_id = MotorId::MD_5345;
- model.flags = GENESYS_FLAG_14BIT_GAMMA |
- GENESYS_FLAG_SEARCH_START |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_SHADING_NO_MOVE |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::GAMMA_14BIT |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_POWER_SW |
GENESYS_HAS_OCR_SW |
GENESYS_HAS_SCAN_SW;
- model.shading_lines = 40;
- model.shading_ta_lines = 0;
model.search_lines = 200;
s_usb_devices->emplace_back(0x0461, 0x0377, model);
@@ -1735,15 +1623,9 @@ void genesys_init_usb_device_tables()
model.y_size = 511;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 433.4934;
model.post_scan = 26.5;
// this is larger than needed -- accounts for second sensor head, which is a calibration item
@@ -1760,13 +1642,9 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::XP300;
model.motor_id = MotorId::XP300;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a7, 0x0474, model);
@@ -1795,15 +1673,9 @@ void genesys_init_usb_device_tables()
model.y_size = 511;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 105.664;
model.post_scan = 17.5;
model.eject_feed = 0.0;
@@ -1820,13 +1692,9 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::DP665;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x0a82, 0x4803, model);
@@ -1855,15 +1723,9 @@ void genesys_init_usb_device_tables()
model.y_size = 511;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 220.1334;
model.post_scan = 16.0;
model.eject_feed = 0.0;
@@ -1880,13 +1742,9 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::ROADWARRIOR;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_DARK_CALIBRATION;
+ model.flags = ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a7, 0x0494, model);
@@ -1915,15 +1773,9 @@ void genesys_init_usb_device_tables()
model.y_size = 511;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 220.1334;
model.post_scan = 16.0;
model.eject_feed = 0.0;
@@ -1940,13 +1792,12 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::ROADWARRIOR;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_NO_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_UNTESTED;
+ model.flags = ModelFlag::DISABLE_ADC_CALIBRATION |
+ ModelFlag::DISABLE_EXPOSURE_CALIBRATION |
+ ModelFlag::DISABLE_SHADING_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::UNTESTED;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW;
- model.shading_lines = 300;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x0a82, 0x4802, model);
@@ -1976,15 +1827,9 @@ void genesys_init_usb_device_tables()
model.y_size = 511;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 220.1334;
model.post_scan = 16.0;
model.eject_feed = 0.0;
@@ -2001,13 +1846,9 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::ROADWARRIOR;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_DARK_CALIBRATION;
+ model.flags = ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a7, 0x049b, model);
@@ -2036,15 +1877,9 @@ void genesys_init_usb_device_tables()
model.y_size = 511;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 220.1334;
model.post_scan = 16.0;
model.eject_feed = 0.0;
@@ -2061,13 +1896,9 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_DSM600;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::DSMOBILE_600;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_DARK_CALIBRATION;
+ model.flags = ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x0a17, 0x3210, model);
@@ -2098,15 +1929,9 @@ void genesys_init_usb_device_tables()
model.y_size = 511;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 220.1334;
model.post_scan = 16.0;
model.eject_feed = 0.0;
@@ -2122,13 +1947,9 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_DSM600;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::DSMOBILE_600;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_DARK_CALIBRATION;
+ model.flags = ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x1dcc, 0x4812, model);
@@ -2157,15 +1978,9 @@ void genesys_init_usb_device_tables()
model.y_size = 500;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 212.5134;
model.post_scan = 26.5;
// this is larger than needed -- accounts for second sensor head, which is a calibration item
@@ -2182,13 +1997,9 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_DSM600;
model.gpio_id = GpioId::DP685;
model.motor_id = MotorId::XP300;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_DARK_CALIBRATION;
+ model.flags = ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 400;
@@ -2219,15 +2030,9 @@ void genesys_init_usb_device_tables()
model.y_size = 511;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 433.4934;
model.post_scan = 26.5;
// this is larger than needed -- accounts for second sensor head, which is a calibration item
@@ -2244,13 +2049,9 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::XP300;
model.motor_id = MotorId::XP300;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_DARK_CALIBRATION;
+ model.flags = ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x0a82, 0x4800, model);
@@ -2280,19 +2081,14 @@ void genesys_init_usb_device_tables()
model.y_size = 511;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 433.4934;
model.post_scan = 26.5;
// this is larger than needed -- accounts for second sensor head, which is a calibration item
model.eject_feed = 0.0;
+
model.ld_shift_r = 0;
model.ld_shift_g = 0;
model.ld_shift_b = 0;
@@ -2301,18 +2097,14 @@ void genesys_init_usb_device_tables()
model.is_cis = true;
model.is_sheetfed = true;
- model.sensor_id = SensorId::CCD_XP300;
+ model.sensor_id = SensorId::CCD_DOCKETPORT_487;
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::XP300;
model.motor_id = MotorId::XP300;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_UNTESTED;
+ model.flags = ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::UNTESTED;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x1dcc, 0x4810, model);
@@ -2337,26 +2129,20 @@ void genesys_init_usb_device_tables()
model.bpp_color_values = { 8, 16 };
model.x_offset = 4.00;
- model.y_offset = 0.80;
+ model.y_offset = 5.0; // FIXME: incorrect, needs updating
model.x_size = 215.9;
model.y_size = 296.4;
model.y_offset_calib_white = 0.00;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.00;
-
- model.x_offset_ta = 0.00;
- model.y_offset_ta = 0.00;
- model.x_size_ta = 0.00;
- model.y_size_ta = 0.00;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.00;
+ model.x_size_calib_mm = 230.1241;
model.post_scan = 0.0;
model.eject_feed = 0.0;
- model.ld_shift_r = 48;
- model.ld_shift_g = 24;
+ model.ld_shift_r = 96;
+ model.ld_shift_g = 48;
model.ld_shift_b = 0;
model.line_mode_color_order = ColorOrder::RGB;
@@ -2366,18 +2152,15 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_5345;
model.gpio_id = GpioId::MD_5345;
model.motor_id = MotorId::MD_5345;
- model.flags = GENESYS_FLAG_14BIT_GAMMA |
- GENESYS_FLAG_SEARCH_START |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::GAMMA_14BIT |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_POWER_SW |
GENESYS_HAS_OCR_SW |
GENESYS_HAS_SCAN_SW;
- model.shading_lines = 40;
- model.shading_ta_lines = 0;
model.search_lines = 200;
s_usb_devices->emplace_back(0x04a7, 0x0229, model);
@@ -2402,26 +2185,20 @@ void genesys_init_usb_device_tables()
model.bpp_color_values = { 8, 16 };
model.x_offset = 4.00;
- model.y_offset = 0.80;
+ model.y_offset = 5.0; // FIXME: incorrect, needs updating
model.x_size = 215.9;
model.y_size = 296.4;
model.y_offset_calib_white = 0.00;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.00;
-
- model.x_offset_ta = 0.00;
- model.y_offset_ta = 0.00;
- model.x_size_ta = 0.00;
- model.y_size_ta = 0.00;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.00;
+ model.x_size_calib_mm = 230.1241;
model.post_scan = 0.0;
model.eject_feed = 0.0;
- model.ld_shift_r = 48;
- model.ld_shift_g = 24;
+ model.ld_shift_r = 96;
+ model.ld_shift_g = 48;
model.ld_shift_b = 0;
model.line_mode_color_order = ColorOrder::RGB;
@@ -2431,18 +2208,15 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_5345;
model.gpio_id = GpioId::MD_5345;
model.motor_id = MotorId::MD_5345;
- model.flags = GENESYS_FLAG_14BIT_GAMMA |
- GENESYS_FLAG_SEARCH_START |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::GAMMA_14BIT |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW |
GENESYS_HAS_EMAIL_SW |
GENESYS_HAS_POWER_SW |
GENESYS_HAS_OCR_SW |
GENESYS_HAS_SCAN_SW;
- model.shading_lines = 40;
- model.shading_ta_lines = 0;
model.search_lines = 200;
s_usb_devices->emplace_back(0x0461, 0x038b, model);
@@ -2472,15 +2246,9 @@ void genesys_init_usb_device_tables()
model.y_size = 511;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 220.1334;
model.post_scan = 16.0;
model.eject_feed = 0.0;
@@ -2497,13 +2265,9 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::WOLFSON_XP300;
model.gpio_id = GpioId::DP665;
model.motor_id = MotorId::ROADWARRIOR;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_DARK_CALIBRATION;
+ model.flags = ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 400;
s_usb_devices->emplace_back(0x04a7, 0x04ac, model);
@@ -2533,15 +2297,9 @@ void genesys_init_usb_device_tables()
model.y_size = 297.0;
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 0.0;
- model.y_size_ta = 0.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 213.7834;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -2558,19 +2316,81 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::PLUSTEK_OPTICPRO_3600;
model.gpio_id = GpioId::PLUSTEK_OPTICPRO_3600;
model.motor_id = MotorId::PLUSTEK_OPTICPRO_3600;
- model.flags = GENESYS_FLAG_UNTESTED | // not fully working yet
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION;
+ model.flags = ModelFlag::UNTESTED | // not fully working yet
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION;
model.buttons = GENESYS_HAS_NO_BUTTONS;
- model.shading_lines = 7;
- model.shading_ta_lines = 0;
model.search_lines = 200;
s_usb_devices->emplace_back(0x07b3, 0x0900, model);
+
+ model = Genesys_Model();
+ model.name = "plustek-opticfilm-7200";
+ model.vendor = "PLUSTEK";
+ model.model = "OpticFilm 7200";
+ model.model_id = ModelId::PLUSTEK_OPTICFILM_7200;
+ model.asic_type = AsicType::GL842;
+
+ model.resolutions = {
+ {
+ { ScanMethod::TRANSPARENCY },
+ { 7200, 3600, 1800, 900 },
+ { 7200, 3600, 1800, 900 },
+ }
+ };
+
+ model.bpp_gray_values = { 16 };
+ model.bpp_color_values = { 16 };
+ model.default_method = ScanMethod::TRANSPARENCY;
+
+ model.x_offset = 0.0;
+ model.y_offset = 0.0;
+ model.x_size = 36.0;
+ model.y_size = 44.0;
+
+ model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 0.0;
+ model.x_offset_calib_black = 6.5;
+ model.x_size_calib_mm = 35.9834;
+
+ model.x_offset_ta = 0.7f;
+ model.y_offset_ta = 28.0;
+ model.x_size_ta = 36.0;
+ model.y_size_ta = 25.0;
+
+ model.y_offset_sensor_to_ta = 0.0;
+ model.y_offset_calib_black_ta = 6.5;
+ model.y_offset_calib_white_ta = 0.0;
+ model.y_size_calib_ta_mm = 2.0;
+
+ model.post_scan = 0.0;
+ model.eject_feed = 0.0;
+
+ model.ld_shift_r = 0;
+ model.ld_shift_g = 12;
+ model.ld_shift_b = 24;
+
+ model.line_mode_color_order = ColorOrder::RGB;
+
+ model.is_cis = false;
+ model.is_sheetfed = false;
+
+ model.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7200;
+ model.adc_id = AdcId::PLUSTEK_OPTICFILM_7200;
+ model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7200;
+ model.motor_id = MotorId::PLUSTEK_OPTICFILM_7200;
+
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK;
+
+ model.search_lines = 200;
+ s_usb_devices->emplace_back(0x07b3, 0x0807, model);
+
+
model = Genesys_Model();
model.name = "plustek-opticfilm-7200i";
model.vendor = "PLUSTEK";
@@ -2594,16 +2414,22 @@ void genesys_init_usb_device_tables()
model.y_offset = 0.0;
model.x_size = 36.0;
model.y_size = 44.0;
+
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 0.0;
model.x_offset_calib_black = 6.5;
+ model.x_size_calib_mm = 35.9834;
model.x_offset_ta = 0.0;
model.y_offset_ta = 29.0;
model.x_size_ta = 36.0;
model.y_size_ta = 24.0;
+
model.y_offset_sensor_to_ta = 0.0;
model.y_offset_calib_black_ta = 6.5;
model.y_offset_calib_white_ta = 0.0;
+ model.y_size_calib_ta_mm = 2.0;
+
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -2621,23 +2447,29 @@ void genesys_init_usb_device_tables()
model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7200I;
model.motor_id = MotorId::PLUSTEK_OPTICFILM_7200I;
- model.flags = GENESYS_FLAG_HAS_UTA |
- GENESYS_FLAG_HAS_UTA_INFRARED |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_HAS_NO_BUTTONS |
- GENESYS_FLAG_SHADING_REPARK |
- GENESYS_FLAG_CALIBRATION_HOST_SIDE |
- GENESYS_FLAG_16BIT_DATA_INVERTED;
-
- model.shading_lines = 7;
- model.shading_ta_lines = 50;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK |
+ ModelFlag::SWAP_16BIT_DATA;
+
model.search_lines = 200;
s_usb_devices->emplace_back(0x07b3, 0x0c04, model);
+ // same as 7200i, just without the infrared channel
+ model.name = "plustek-opticfilm-7200-v2";
+ model.model = "OpticFilm 7200 v2";
+ model.resolutions = {
+ {
+ { ScanMethod::TRANSPARENCY },
+ { 7200, 3600, 1800, 900 },
+ { 7200, 3600, 1800, 900 },
+ }
+ };
+ s_usb_devices->emplace_back(0x07b3, 0x0c07, model);
+
+
model = Genesys_Model();
model.name = "plustek-opticfilm-7300";
model.vendor = "PLUSTEK";
@@ -2661,16 +2493,22 @@ void genesys_init_usb_device_tables()
model.y_offset = 0.0;
model.x_size = 36.0;
model.y_size = 44.0;
+
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 0.0;
model.x_offset_calib_black = 6.5;
+ model.x_size_calib_mm = 35.9834;
model.x_offset_ta = 0.0;
model.y_offset_ta = 29.0;
model.x_size_ta = 36.0;
model.y_size_ta = 24.0;
+
model.y_offset_sensor_to_ta = 0.0;
model.y_offset_calib_black_ta = 6.5;
model.y_offset_calib_white_ta = 0.0;
+ model.y_size_calib_ta_mm = 2.0;
+
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -2688,21 +2526,91 @@ void genesys_init_usb_device_tables()
model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7300;
model.motor_id = MotorId::PLUSTEK_OPTICFILM_7300;
- model.flags = GENESYS_FLAG_HAS_UTA |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_HAS_NO_BUTTONS |
- GENESYS_FLAG_SHADING_REPARK |
- GENESYS_FLAG_CALIBRATION_HOST_SIDE;
-
- model.shading_lines = 7;
- model.shading_ta_lines = 50;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK;
+
model.search_lines = 200;
s_usb_devices->emplace_back(0x07b3, 0x0c12, model);
+ // same as 7300, same USB ID as 7400-v2
+ model.name = "plustek-opticfilm-7400-v1";
+ model.model = "OpticFilm 7400 (v1)";
+ s_usb_devices->emplace_back(0x07b3, 0x0c3a, 0x0400, model);
+
+
+ model = Genesys_Model();
+ model.name = "plustek-opticfilm-7400-v2";
+ model.vendor = "PLUSTEK";
+ model.model = "OpticFilm 7400 (v2)";
+ model.model_id = ModelId::PLUSTEK_OPTICFILM_7400;
+ model.asic_type = AsicType::GL845;
+
+ model.resolutions = {
+ {
+ { ScanMethod::TRANSPARENCY },
+ { 7200, 3600, 2400, 1200, 600 },
+ { 7200, 3600, 2400, 1200, 600 },
+ }
+ };
+
+ model.bpp_gray_values = { 16 };
+ model.bpp_color_values = { 16 };
+ model.default_method = ScanMethod::TRANSPARENCY;
+
+ model.x_offset = 0.0;
+ model.y_offset = 0.0;
+ model.x_size = 36.0;
+ model.y_size = 44.0;
+
+ model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 0.0;
+ model.x_offset_calib_black = 6.5;
+ model.x_size_calib_mm = 36.83;
+
+ model.x_offset_ta = 0.5;
+ model.y_offset_ta = 29.0;
+ model.x_size_ta = 36.33;
+ model.y_size_ta = 25.0;
+
+ model.y_offset_sensor_to_ta = 0.0;
+ model.y_offset_calib_black_ta = 6.5;
+ model.y_offset_calib_white_ta = 0.0;
+ model.y_size_calib_ta_mm = 2.0;
+
+ model.post_scan = 0.0;
+ model.eject_feed = 0.0;
+
+ model.ld_shift_r = 0;
+ model.ld_shift_g = 12;
+ model.ld_shift_b = 24;
+
+ model.line_mode_color_order = ColorOrder::RGB;
+
+ model.is_cis = false;
+ model.is_sheetfed = false;
+
+ model.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7400;
+ model.adc_id = AdcId::PLUSTEK_OPTICFILM_7400;
+ model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7400;
+ model.motor_id = MotorId::PLUSTEK_OPTICFILM_7400;
+
+ model.flags = ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK;
+
+ model.search_lines = 200;
+ s_usb_devices->emplace_back(0x07b3, 0x0c3a, 0x0605, model);
+
+
+ // same as 7400-v2
+ model.name = "plustek-opticfilm-8100";
+ model.model = "OpticFilm 8100";
+ s_usb_devices->emplace_back(0x07b3, 0x130c, model);
+
+
model = Genesys_Model();
model.name = "plustek-opticfilm-7500i";
model.vendor = "PLUSTEK";
@@ -2726,16 +2634,22 @@ void genesys_init_usb_device_tables()
model.y_offset = 0.0;
model.x_size = 36.0;
model.y_size = 44.0;
+
model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 0.0;
model.x_offset_calib_black = 6.5;
model.x_offset_ta = 0.0;
model.y_offset_ta = 29.0;
model.x_size_ta = 36.0;
model.y_size_ta = 24.0;
+ model.x_size_calib_mm = 35.9834;
+
model.y_offset_sensor_to_ta = 0.0;
model.y_offset_calib_black_ta = 6.5;
model.y_offset_calib_white_ta = 0.0;
+ model.y_size_calib_ta_mm = 2.0;
+
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -2753,22 +2667,91 @@ void genesys_init_usb_device_tables()
model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7500I;
model.motor_id = MotorId::PLUSTEK_OPTICFILM_7500I;
- model.flags = GENESYS_FLAG_HAS_UTA |
- GENESYS_FLAG_HAS_UTA_INFRARED |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_HAS_NO_BUTTONS |
- GENESYS_FLAG_SHADING_REPARK |
- GENESYS_FLAG_CALIBRATION_HOST_SIDE;
-
- model.shading_lines = 7;
- model.shading_ta_lines = 50;
+ model.flags = ModelFlag::WARMUP |
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK;
+
model.search_lines = 200;
s_usb_devices->emplace_back(0x07b3, 0x0c13, model);
+ // same as 7500i
+ model.name = "plustek-opticfilm-7600i-v1";
+ model.model = "OpticFilm 7600i (v1)";
+ s_usb_devices->emplace_back(0x07b3, 0x0c3b, 0x0400, model);
+
+
+ model = Genesys_Model();
+ model.name = "plustek-opticfilm-8200i";
+ model.vendor = "PLUSTEK";
+ model.model = "OpticFilm 8200i";
+ model.model_id = ModelId::PLUSTEK_OPTICFILM_8200I;
+ model.asic_type = AsicType::GL845;
+
+ model.resolutions = {
+ {
+ { ScanMethod::TRANSPARENCY, ScanMethod::TRANSPARENCY_INFRARED },
+ { 7200, 3600, 1800, 900 },
+ { 7200, 3600, 1800, 900 },
+ }
+ };
+
+ model.bpp_gray_values = { 16 };
+ model.bpp_color_values = { 16 };
+ model.default_method = ScanMethod::TRANSPARENCY;
+
+ model.x_offset = 0.0;
+ model.y_offset = 0.0;
+ model.x_size = 36.0;
+ model.y_size = 44.0;
+
+ model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 0.0;
+ model.x_offset_calib_black = 6.5;
+ model.x_size_calib_mm = 36.83;
+
+ model.x_offset_ta = 0.5;
+ model.y_offset_ta = 28.5;
+ model.x_size_ta = 36.33;
+ model.y_size_ta = 25.0;
+
+ model.y_offset_sensor_to_ta = 0.0;
+ model.y_offset_calib_black_ta = 6.5;
+ model.y_offset_calib_white_ta = 0.0;
+ model.y_size_calib_ta_mm = 2.0;
+
+ model.post_scan = 0.0;
+ model.eject_feed = 0.0;
+
+ model.ld_shift_r = 0;
+ model.ld_shift_g = 12;
+ model.ld_shift_b = 24;
+
+ model.line_mode_color_order = ColorOrder::RGB;
+
+ model.is_cis = false;
+ model.is_sheetfed = false;
+
+ model.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_8200I;
+ model.adc_id = AdcId::PLUSTEK_OPTICFILM_8200I;
+ model.gpio_id = GpioId::PLUSTEK_OPTICFILM_8200I;
+ model.motor_id = MotorId::PLUSTEK_OPTICFILM_8200I;
+
+ model.flags = ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::SHADING_REPARK;
+
+ model.search_lines = 200;
+ s_usb_devices->emplace_back(0x07b3, 0x130d, model);
+
+
+ // same as 8200i
+ model.name = "plustek-opticfilm-7600i-v2";
+ model.model = "OpticFilm 7600i (v2)";
+ s_usb_devices->emplace_back(0x07b3, 0x0c3b, 0x0605, model);
+
+
model = Genesys_Model();
model.name = "hewlett-packard-scanjet-N6310";
model.vendor = "Hewlett Packard";
@@ -2792,16 +2775,10 @@ void genesys_init_usb_device_tables()
model.x_size = 216;
model.y_size = 511;
- model.y_offset_calib_white = 3.0;
+ model.y_offset_calib_white = 0.0;
+ model.y_size_calib_mm = 4.0; // FIXME: y_offset is liely incorrect
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 100.0;
- model.y_size_ta = 100.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0;
+ model.x_size_calib_mm = 452.12;
model.post_scan = 0;
model.eject_feed = 0;
@@ -2818,17 +2795,15 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::CANON_LIDE_200; // Not defined yet for N6310
model.gpio_id = GpioId::HP_N6310;
model.motor_id = MotorId::CANON_LIDE_200; // Not defined yet for N6310
- model.flags = GENESYS_FLAG_UNTESTED |
- GENESYS_FLAG_14BIT_GAMMA |
- GENESYS_FLAG_DARK_CALIBRATION |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_NO_CALIBRATION;
+ model.flags = ModelFlag::UNTESTED |
+ ModelFlag::GAMMA_14BIT |
+ ModelFlag::DARK_CALIBRATION |
+ ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::DISABLE_ADC_CALIBRATION |
+ ModelFlag::DISABLE_EXPOSURE_CALIBRATION |
+ ModelFlag::DISABLE_SHADING_CALIBRATION;
model.buttons = GENESYS_HAS_NO_BUTTONS;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 100;
s_usb_devices->emplace_back(0x03f0, 0x4705, model);
@@ -2858,15 +2833,9 @@ void genesys_init_usb_device_tables()
model.y_size = 300.0;
model.y_offset_calib_white = 9.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 0.0;
- model.y_size_ta = 0.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 215.9;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -2883,12 +2852,8 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::PLUSTEK_OPTICBOOK_3800;
model.gpio_id = GpioId::PLUSTEK_OPTICBOOK_3800;
model.motor_id = MotorId::PLUSTEK_OPTICBOOK_3800;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA;
+ model.flags = ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_NO_BUTTONS; // TODO there are 4 buttons to support
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 100;
s_usb_devices->emplace_back(0x07b3, 0x1300, model);
@@ -2918,15 +2883,9 @@ void genesys_init_usb_device_tables()
model.y_size = 300.0;
model.y_offset_calib_white = 9.0;
+ model.y_size_calib_mm = 4.0;
model.x_offset_calib_black = 0.0;
-
- model.x_offset_ta = 0.0;
- model.y_offset_ta = 0.0;
- model.x_size_ta = 0.0;
- model.y_size_ta = 0.0;
-
- model.y_offset_sensor_to_ta = 0.0;
- model.y_offset_calib_white_ta = 0.0;
+ model.x_size_calib_mm = 228.6;
model.post_scan = 0.0;
model.eject_feed = 0.0;
@@ -2943,16 +2902,36 @@ void genesys_init_usb_device_tables()
model.adc_id = AdcId::IMG101;
model.gpio_id = GpioId::IMG101;
model.motor_id = MotorId::IMG101;
- model.flags = GENESYS_FLAG_SKIP_WARMUP |
- GENESYS_FLAG_OFFSET_CALIBRATION |
- GENESYS_FLAG_CUSTOM_GAMMA |
- GENESYS_FLAG_UNTESTED;
+ model.flags = ModelFlag::CUSTOM_GAMMA |
+ ModelFlag::UNTESTED;
model.buttons = GENESYS_HAS_NO_BUTTONS ;
- model.shading_lines = 100;
- model.shading_ta_lines = 0;
model.search_lines = 100;
s_usb_devices->emplace_back(0x1083, 0x162e, model);
- }
+}
+
+void verify_usb_device_tables()
+{
+ for (const auto& device : *s_usb_devices) {
+ const auto& model = device.model();
+
+ if (model.x_size_calib_mm == 0.0f) {
+ throw SaneException("Calibration width can't be zero");
+ }
+
+ if (model.has_method(ScanMethod::FLATBED)) {
+ if (model.y_size_calib_mm == 0.0f) {
+ throw SaneException("Calibration size can't be zero");
+ }
+ }
+ if (model.has_method(ScanMethod::TRANSPARENCY) ||
+ model.has_method(ScanMethod::TRANSPARENCY_INFRARED))
+ {
+ if (model.y_size_calib_ta_mm == 0.0f) {
+ throw SaneException("Calibration size can't be zero");
+ }
+ }
+ }
+}
} // namespace genesys
diff --git a/backend/genesys/tables_motor.cpp b/backend/genesys/tables_motor.cpp
index 2484d2d..a452fe5 100644
--- a/backend/genesys/tables_motor.cpp
+++ b/backend/genesys/tables_motor.cpp
@@ -53,272 +53,586 @@ 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::CANON_LIDE_90;
+ motor.base_ydpi = 1200;
+ profile = {MotorSlope::create_from_steps(8000, 3000, 200), StepType::FULL, 0};
+ profile.resolutions = { 150, 300 };
+ motor.profiles.push_back(profile);
+
+ profile = {MotorSlope::create_from_steps(7000, 3000, 200), StepType::HALF, 0};
+ profile.resolutions = { 600, 1200 };
+ motor.profiles.push_back(profile);
+
+ profile = {MotorSlope::create_from_steps(7000, 3000, 200), StepType::QUARTER, 0};
+ profile.resolutions = { 2400 };
+ motor.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_5600F;
+ motor.base_ydpi = 2400;
+
+ // FIXME: real limit is 134, but for some reason the motor can't acquire that speed.
+ profile = MotorProfile();
+ profile.slope = MotorSlope::create_from_steps(2500 * 2, 134 * 2, 1000);
+ profile.step_type = StepType::HALF;
+ profile.motor_vref = 0;
+ profile.resolutions = { 75, 150 };
+ motor.profiles.push_back(std::move(profile));
+
+ profile = MotorProfile();
+ profile.slope = MotorSlope::create_from_steps(2500 * 2, 200 * 2, 1000);
+ profile.step_type = StepType::QUARTER;
+ profile.motor_vref = 0;
+ profile.resolutions = { 300, 600, 1200, 2400, 4800 };
+ motor.profiles.push_back(std::move(profile));
+
+ profile = MotorProfile();
+ profile.slope = MotorSlope::create_from_steps(2500 * 2, 200 * 2, 1000);
+ profile.step_type = StepType::QUARTER;
+ profile.motor_vref = 0;
+ motor.fast_profiles.push_back(std::move(profile));
+
s_motors->push_back(std::move(motor));
motor = Genesys_Motor();
motor.id = MotorId::CANON_8400F;
motor.base_ydpi = 1600;
- motor.optical_ydpi = 6400;
- 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));
}
diff --git a/backend/genesys/tables_motor_profile.cpp b/backend/genesys/tables_motor_profile.cpp
deleted file mode 100644
index 18f7271..0000000
--- a/backend/genesys/tables_motor_profile.cpp
+++ /dev/null
@@ -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
diff --git a/backend/genesys/tables_sensor.cpp b/backend/genesys/tables_sensor.cpp
index bbbe441..b90355c 100644
--- a/backend/genesys/tables_sensor.cpp
+++ b/backend/genesys/tables_sensor.cpp
@@ -44,71 +44,10 @@
#define DEBUG_DECLARE_ONLY
#include "low.h"
+#include <map>
namespace genesys {
-inline unsigned default_get_logical_hwdpi(const Genesys_Sensor& sensor, unsigned xres)
-{
- if (sensor.logical_dpihw_override)
- return sensor.logical_dpihw_override;
-
- // can't be below 600 dpi
- if (xres <= 600) {
- return 600;
- }
- if (xres <= static_cast<unsigned>(sensor.optical_res) / 4) {
- return sensor.optical_res / 4;
- }
- if (xres <= static_cast<unsigned>(sensor.optical_res) / 2) {
- return sensor.optical_res / 2;
- }
- return sensor.optical_res;
-}
-
-inline unsigned get_sensor_optical_with_ccd_divisor(const Genesys_Sensor& sensor, unsigned xres)
-{
- unsigned hwres = sensor.optical_res / sensor.get_ccd_size_divisor_for_dpi(xres);
-
- if (xres <= hwres / 4) {
- return hwres / 4;
- }
- if (xres <= hwres / 2) {
- return hwres / 2;
- }
- return hwres;
-}
-
-inline unsigned default_get_ccd_size_divisor_for_dpi(const Genesys_Sensor& sensor, unsigned xres)
-{
- if (sensor.ccd_size_divisor >= 4 && xres * 4 <= static_cast<unsigned>(sensor.optical_res)) {
- return 4;
- }
- if (sensor.ccd_size_divisor >= 2 && xres * 2 <= static_cast<unsigned>(sensor.optical_res)) {
- return 2;
- }
- return 1;
-}
-
-inline unsigned get_ccd_size_divisor_exact(const Genesys_Sensor& sensor, unsigned xres)
-{
- (void) xres;
- return sensor.ccd_size_divisor;
-}
-
-inline unsigned get_ccd_size_divisor_gl124(const Genesys_Sensor& sensor, unsigned xres)
-{
- // we have 2 domains for ccd: xres below or above half ccd max dpi
- if (xres <= 300 && sensor.ccd_size_divisor > 1) {
- return 2;
- }
- return 1;
-}
-
-inline unsigned default_get_hwdpi_divisor_for_dpi(const Genesys_Sensor& sensor, unsigned xres)
-{
- return sensor.optical_res / default_get_logical_hwdpi(sensor, xres);
-}
-
StaticInit<std::vector<Genesys_Sensor>> s_sensors;
void genesys_init_sensor_tables()
@@ -118,444 +57,231 @@ void genesys_init_sensor_tables()
Genesys_Sensor sensor;
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_UMAX;
- sensor.optical_res = 1200;
+ sensor.sensor_id = SensorId::CCD_UMAX; // gl646
+ sensor.full_resolution = 1200;
sensor.black_pixels = 48;
sensor.dummy_pixel = 64;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10800;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 230;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
sensor.custom_regs = {
- { 0x08, 0x01 },
- { 0x09, 0x03 },
- { 0x0a, 0x05 },
- { 0x0b, 0x07 },
- { 0x16, 0x33 },
- { 0x17, 0x05 },
- { 0x18, 0x31 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x02 },
- { 0x52, 0x13 },
- { 0x53, 0x17 },
- { 0x54, 0x03 },
- { 0x55, 0x07 },
- { 0x56, 0x0b },
- { 0x57, 0x0f },
- { 0x58, 0x23 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 },
+ { 0x08, 0x01 }, { 0x09, 0x03 }, { 0x0a, 0x05 }, { 0x0b, 0x07 },
+ { 0x16, 0x33 }, { 0x17, 0x05 }, { 0x18, 0x31 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x02 },
+ { 0x52, 0x13 }, { 0x53, 0x17 }, { 0x54, 0x03 }, { 0x55, 0x07 },
+ { 0x56, 0x0b }, { 0x57, 0x0f }, { 0x58, 0x23 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 150, 4 },
+ { { 150 }, 300, 8 },
+ { { 300 }, 600, 16 },
+ { { 600 }, 1200, 32 },
+ { { 1200 }, 2400, 64 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_ST12;
- sensor.optical_res = 600;
+ sensor.sensor_id = SensorId::CCD_ST12; // gl646
+ sensor.full_resolution = 600;
sensor.black_pixels = 48;
sensor.dummy_pixel = 85;
- sensor.ccd_start_xoffset = 152;
- sensor.sensor_pixels = 5416;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 230;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
sensor.custom_regs = {
- { 0x08, 0x02 },
- { 0x09, 0x00 },
- { 0x0a, 0x06 },
- { 0x0b, 0x04 },
- { 0x16, 0x2b },
- { 0x17, 0x08 },
- { 0x18, 0x20 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x0c },
- { 0x1d, 0x03 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 },
+ { 0x08, 0x02 }, { 0x09, 0x00 }, { 0x0a, 0x06 }, { 0x0b, 0x04 },
+ { 0x16, 0x2b }, { 0x17, 0x08 }, { 0x18, 0x20 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x0c }, { 0x1d, 0x03 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 10 },
+ { { 150 }, 21 },
+ { { 300 }, 42 },
+ { { 600 }, 85 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.resolutions.values()[0];
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_ST24;
- sensor.optical_res = 1200;
+ sensor.sensor_id = SensorId::CCD_ST24; // gl646
+ sensor.full_resolution = 1200;
sensor.black_pixels = 48;
sensor.dummy_pixel = 64;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10800;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 230;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
sensor.custom_regs = {
- { 0x08, 0x0e },
- { 0x09, 0x0c },
- { 0x0a, 0x00 },
- { 0x0b, 0x0c },
- { 0x16, 0x33 },
- { 0x17, 0x08 },
- { 0x18, 0x31 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x02 },
- { 0x52, 0x17 },
- { 0x53, 0x03 },
- { 0x54, 0x07 },
- { 0x55, 0x0b },
- { 0x56, 0x0f },
- { 0x57, 0x13 },
- { 0x58, 0x03 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 },
+ { 0x08, 0x0e }, { 0x09, 0x0c }, { 0x0a, 0x00 }, { 0x0b, 0x0c },
+ { 0x16, 0x33 }, { 0x17, 0x08 }, { 0x18, 0x31 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x02 },
+ { 0x52, 0x17 }, { 0x53, 0x03 }, { 0x54, 0x07 }, { 0x55, 0x0b },
+ { 0x56, 0x0f }, { 0x57, 0x13 }, { 0x58, 0x03 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 150, 4 },
+ { { 150 }, 300, 8 },
+ { { 300 }, 600, 16 },
+ { { 600 }, 1200, 32 },
+ { { 1200 }, 2400, 64 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_5345;
- sensor.optical_res = 1200;
- sensor.ccd_size_divisor = 2;
+ sensor.sensor_id = SensorId::CCD_5345; // gl646
+ sensor.full_resolution = 1200;
sensor.black_pixels = 48;
sensor.dummy_pixel = 16;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10872;
sensor.fau_gain_white_ref = 190;
sensor.gain_white_ref = 190;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
- sensor.stagger_config = StaggerConfig{ 1200, 4 }; // FIXME: may be incorrect
- sensor.custom_base_regs = {
- { 0x08, 0x0d },
- { 0x09, 0x0f },
- { 0x0a, 0x11 },
- { 0x0b, 0x13 },
- { 0x16, 0x0b },
- { 0x17, 0x0a },
- { 0x18, 0x30 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x03 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x23 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 },
- };
sensor.gamma = { 2.38f, 2.35f, 2.34f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpiset;
unsigned exposure_lperiod;
- unsigned ccd_size_divisor;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
+ StaggerConfig stagger_y; // FIXME: may be incorrect
GenesysRegisterSettingSet custom_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 50 }, 12000, 2, {
- { 0x08, 0x00 },
- { 0x09, 0x05 },
- { 0x0a, 0x06 },
- { 0x0b, 0x08 },
- { 0x16, 0x0b },
- { 0x17, 0x0a },
- { 0x18, 0x28 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x03 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 75 }, 11000, 2, {
- { 0x08, 0x00 },
- { 0x09, 0x05 },
- { 0x0a, 0x06 },
- { 0x0b, 0x08 },
- { 0x16, 0x0b },
- { 0x17, 0x0a },
- { 0x18, 0x28 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x03 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 100 }, 11000, 2, {
- { 0x08, 0x00 },
- { 0x09, 0x05 },
- { 0x0a, 0x06 },
- { 0x0b, 0x08 },
- { 0x16, 0x0b },
- { 0x17, 0x0a },
- { 0x18, 0x28 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x03 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 150 }, 11000, 2, {
- { 0x08, 0x00 },
- { 0x09, 0x05 },
- { 0x0a, 0x06 },
- { 0x0b, 0x08 },
- { 0x16, 0x0b },
- { 0x17, 0x0a },
- { 0x18, 0x28 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x03 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 200 }, 11000, 2, {
- { 0x08, 0x00 },
- { 0x09, 0x05 },
- { 0x0a, 0x06 },
- { 0x0b, 0x08 },
- { 0x16, 0x0b },
- { 0x17, 0x0a },
- { 0x18, 0x28 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x03 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 300 }, 11000, 2, {
- { 0x08, 0x00 },
- { 0x09, 0x05 },
- { 0x0a, 0x06 },
- { 0x0b, 0x08 },
- { 0x16, 0x0b },
- { 0x17, 0x0a },
- { 0x18, 0x28 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x03 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 400 }, 11000, 2, {
- { 0x08, 0x00 },
- { 0x09, 0x05 },
- { 0x0a, 0x06 },
- { 0x0b, 0x08 },
- { 0x16, 0x0b },
- { 0x17, 0x0a },
- { 0x18, 0x28 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x03 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 600 }, 11000, 2, {
- { 0x08, 0x00 },
- { 0x09, 0x05 },
- { 0x0a, 0x06 },
- { 0x0b, 0x08 },
- { 0x16, 0x0b },
- { 0x17, 0x0a },
- { 0x18, 0x28 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x03 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 1200 }, 11000, 1, {
- { 0x08, 0x0d },
- { 0x09, 0x0f },
- { 0x0a, 0x11 },
- { 0x0b, 0x13 },
- { 0x16, 0x0b },
- { 0x17, 0x0a },
- { 0x18, 0x30 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x03 },
- { 0x52, 0x03 },
- { 0x53, 0x07 },
- { 0x54, 0x0b },
- { 0x55, 0x0f },
- { 0x56, 0x13 },
- { 0x57, 0x17 },
- { 0x58, 0x23 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
+ { { 50 }, 600, 100, 12000, Ratio{1, 2}, 0, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x05 }, { 0x0a, 0x06 }, { 0x0b, 0x08 },
+ { 0x16, 0x0b }, { 0x17, 0x0a }, { 0x18, 0x28 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x03 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 75 }, 600, 150, 11000, Ratio{1, 2}, 1, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x05 }, { 0x0a, 0x06 }, { 0x0b, 0x08 },
+ { 0x16, 0x0b }, { 0x17, 0x0a }, { 0x18, 0x28 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x03 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 100 }, 600, 200, 11000, Ratio{1, 2}, 1, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x05 }, { 0x0a, 0x06 }, { 0x0b, 0x08 },
+ { 0x16, 0x0b }, { 0x17, 0x0a }, { 0x18, 0x28 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x03 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 150 }, 600, 300, 11000, Ratio{1, 2}, 2, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x05 }, { 0x0a, 0x06 }, { 0x0b, 0x08 },
+ { 0x16, 0x0b }, { 0x17, 0x0a }, { 0x18, 0x28 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x03 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 200 }, 600, 400, 11000, Ratio{1, 2}, 2, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x05 }, { 0x0a, 0x06 }, { 0x0b, 0x08 },
+ { 0x16, 0x0b }, { 0x17, 0x0a }, { 0x18, 0x28 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x03 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 300 }, 600, 600, 11000, Ratio{1, 2}, 4, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x05 }, { 0x0a, 0x06 }, { 0x0b, 0x08 },
+ { 0x16, 0x0b }, { 0x17, 0x0a }, { 0x18, 0x28 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x03 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 400 }, 600, 800, 11000, Ratio{1, 2}, 5, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x05 }, { 0x0a, 0x06 }, { 0x0b, 0x08 },
+ { 0x16, 0x0b }, { 0x17, 0x0a }, { 0x18, 0x28 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x03 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 600 }, 600, 1200, 11000, Ratio{1, 2}, 8, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x05 }, { 0x0a, 0x06 }, { 0x0b, 0x08 },
+ { 0x16, 0x0b }, { 0x17, 0x0a }, { 0x18, 0x28 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x03 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 1200 }, 1200, 1200, 11000, Ratio{1, 1}, 16, StaggerConfig{4, 0}, {
+ { 0x08, 0x0d }, { 0x09, 0x0f }, { 0x0a, 0x11 }, { 0x0b, 0x13 },
+ { 0x16, 0x0b }, { 0x17, 0x0a }, { 0x18, 0x30 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x03 },
+ { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x0b }, { 0x55, 0x0f },
+ { 0x56, 0x13 }, { 0x57, 0x17 }, { 0x58, 0x23 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
}
},
};
@@ -563,8 +289,12 @@ void genesys_init_sensor_tables()
for (const CustomSensorSettings& setting : custom_settings)
{
sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpiset = setting.register_dpiset;
sensor.exposure_lperiod = setting.exposure_lperiod;
- sensor.ccd_size_divisor = setting.ccd_size_divisor;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.stagger_y = setting.stagger_y;
sensor.custom_regs = setting.custom_regs;
s_sensors->push_back(sensor);
}
@@ -572,223 +302,79 @@ void genesys_init_sensor_tables()
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_HP2400;
- sensor.optical_res = 1200;
+ sensor.sensor_id = SensorId::CCD_HP2400; // gl646
+ sensor.full_resolution = 1200;
sensor.black_pixels = 48;
sensor.dummy_pixel = 15;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10872;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
- sensor.stagger_config = StaggerConfig{1200, 4}; // FIXME: may be incorrect
- sensor.custom_base_regs = {
- { 0x08, 0x14 },
- { 0x09, 0x15 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0xbf },
- { 0x17, 0x08 },
- { 0x18, 0x3f },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x02 },
- { 0x52, 0x0b },
- { 0x53, 0x0f },
- { 0x54, 0x13 },
- { 0x55, 0x17 },
- { 0x56, 0x03 },
- { 0x57, 0x07 },
- { 0x58, 0x63 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x0e },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 },
- };
sensor.gamma = { 2.1f, 2.1f, 2.1f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
unsigned exposure_lperiod;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
+ StaggerConfig stagger_y;
GenesysRegisterSettingSet custom_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 50 }, 7211, {
- { 0x08, 0x14 },
- { 0x09, 0x15 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0xbf },
- { 0x17, 0x08 },
- { 0x18, 0x3f },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x02 },
- { 0x52, 0x0b },
- { 0x53, 0x0f },
- { 0x54, 0x13 },
- { 0x55, 0x17 },
- { 0x56, 0x03 },
- { 0x57, 0x07 },
- { 0x58, 0x63 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 100 }, 7211, {
- { 0x08, 0x14 },
- { 0x09, 0x15 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0xbf },
- { 0x17, 0x08 },
- { 0x18, 0x3f },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x02 },
- { 0x52, 0x0b },
- { 0x53, 0x0f },
- { 0x54, 0x13 },
- { 0x55, 0x17 },
- { 0x56, 0x03 },
- { 0x57, 0x07 },
- { 0x58, 0x63 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 150 }, 7211, {
- { 0x08, 0x14 },
- { 0x09, 0x15 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0xbf },
- { 0x17, 0x08 },
- { 0x18, 0x3f },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x02 },
- { 0x52, 0x0b },
- { 0x53, 0x0f },
- { 0x54, 0x13 },
- { 0x55, 0x17 },
- { 0x56, 0x03 },
- { 0x57, 0x07 },
- { 0x58, 0x63 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 300 }, 8751, {
- { 0x08, 0x14 },
- { 0x09, 0x15 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0xbf },
- { 0x17, 0x08 },
- { 0x18, 0x3f },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x02 },
- { 0x52, 0x0b },
- { 0x53, 0x0f },
- { 0x54, 0x13 },
- { 0x55, 0x17 },
- { 0x56, 0x03 },
- { 0x57, 0x07 },
- { 0x58, 0x63 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 600 }, 18760, {
- { 0x08, 0x0e },
- { 0x09, 0x0f },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0xbf },
- { 0x17, 0x08 },
- { 0x18, 0x31 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x02 },
- { 0x52, 0x03 },
- { 0x53, 0x07 },
- { 0x54, 0x0b },
- { 0x55, 0x0f },
- { 0x56, 0x13 },
- { 0x57, 0x17 },
- { 0x58, 0x23 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 1200 }, 21749, {
- { 0x08, 0x02 },
- { 0x09, 0x04 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0xbf },
- { 0x17, 0x08 },
- { 0x18, 0x30 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0xc0 },
- { 0x1d, 0x42 },
- { 0x52, 0x0b },
- { 0x53, 0x0f },
- { 0x54, 0x13 },
- { 0x55, 0x17 },
- { 0x56, 0x03 },
- { 0x57, 0x07 },
- { 0x58, 0x63 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x0e },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
+ { { 50 }, 200, 7211, Ratio{1, 4}, 0, StaggerConfig{}, {
+ { 0x08, 0x14 }, { 0x09, 0x15 }, { 0x0a, 0x00 }, { 0x0b, 0x00 },
+ { 0x16, 0xbf }, { 0x17, 0x08 }, { 0x18, 0x3f }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x02 },
+ { 0x52, 0x0b }, { 0x53, 0x0f }, { 0x54, 0x13 }, { 0x55, 0x17 },
+ { 0x56, 0x03 }, { 0x57, 0x07 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 100 }, 400, 7211, Ratio{1, 4}, 1, StaggerConfig{}, {
+ { 0x08, 0x14 }, { 0x09, 0x15 }, { 0x0a, 0x00 }, { 0x0b, 0x00 },
+ { 0x16, 0xbf }, { 0x17, 0x08 }, { 0x18, 0x3f }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x02 },
+ { 0x52, 0x0b }, { 0x53, 0x0f }, { 0x54, 0x13 }, { 0x55, 0x17 },
+ { 0x56, 0x03 }, { 0x57, 0x07 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 150 }, 600, 7211, Ratio{1, 4}, 1, StaggerConfig{}, {
+ { 0x08, 0x14 }, { 0x09, 0x15 }, { 0x0a, 0x00 }, { 0x0b, 0x00 },
+ { 0x16, 0xbf }, { 0x17, 0x08 }, { 0x18, 0x3f }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x02 },
+ { 0x52, 0x0b }, { 0x53, 0x0f }, { 0x54, 0x13 }, { 0x55, 0x17 },
+ { 0x56, 0x03 }, { 0x57, 0x07 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 300 }, 1200, 8751, Ratio{1, 4}, 3, StaggerConfig{}, {
+ { 0x08, 0x14 }, { 0x09, 0x15 }, { 0x0a, 0x00 }, { 0x0b, 0x00 },
+ { 0x16, 0xbf }, { 0x17, 0x08 }, { 0x18, 0x3f }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x02 },
+ { 0x52, 0x0b }, { 0x53, 0x0f }, { 0x54, 0x13 }, { 0x55, 0x17 },
+ { 0x56, 0x03 }, { 0x57, 0x07 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 600 }, 1200, 18760, Ratio{1, 2}, 7, StaggerConfig{}, {
+ { 0x08, 0x0e }, { 0x09, 0x0f }, { 0x0a, 0x00 }, { 0x0b, 0x00 },
+ { 0x16, 0xbf }, { 0x17, 0x08 }, { 0x18, 0x31 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x02 },
+ { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x0b }, { 0x55, 0x0f },
+ { 0x56, 0x13 }, { 0x57, 0x17 }, { 0x58, 0x23 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 1200 }, 1200, 21749, Ratio{1, 1}, 15, StaggerConfig{4, 0}, {
+ { 0x08, 0x02 }, { 0x09, 0x04 }, { 0x0a, 0x00 }, { 0x0b, 0x00 },
+ { 0x16, 0xbf }, { 0x17, 0x08 }, { 0x18, 0x30 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0xc0 }, { 0x1d, 0x42 },
+ { 0x52, 0x0b }, { 0x53, 0x0f }, { 0x54, 0x13 }, { 0x55, 0x17 },
+ { 0x56, 0x03 }, { 0x57, 0x07 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x0e }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
}
},
};
@@ -796,7 +382,11 @@ void genesys_init_sensor_tables()
for (const CustomSensorSettings& setting : custom_settings)
{
sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.register_dpiset;
sensor.exposure_lperiod = setting.exposure_lperiod;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.stagger_y = setting.stagger_y;
sensor.custom_regs = setting.custom_regs;
s_sensors->push_back(sensor);
}
@@ -804,168 +394,61 @@ void genesys_init_sensor_tables()
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_HP2300;
- sensor.optical_res = 600;
- sensor.ccd_size_divisor = 2;
+ sensor.sensor_id = SensorId::CCD_HP2300; // gl646
+ sensor.full_resolution = 600;
sensor.black_pixels = 48;
sensor.dummy_pixel = 20;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 5368;
sensor.fau_gain_white_ref = 180;
sensor.gain_white_ref = 180;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
- sensor.custom_base_regs = {
- { 0x08, 0x16 },
- { 0x09, 0x00 },
- { 0x0a, 0x01 },
- { 0x0b, 0x03 },
- { 0x16, 0xb7 },
- { 0x17, 0x0a },
- { 0x18, 0x20 },
- { 0x19, 0x2a },
- { 0x1a, 0x6a },
- { 0x1b, 0x8a },
- { 0x1c, 0x00 },
- { 0x1d, 0x05 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x06 },
- { 0x5c, 0x0b },
- { 0x5d, 0x10 },
- { 0x5e, 0x16 },
- };
sensor.gamma = { 2.1f, 2.1f, 2.1f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpiset;
unsigned exposure_lperiod;
- unsigned ccd_size_divisor;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
GenesysRegisterSettingSet custom_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 75 }, 4480, 2, {
- { 0x08, 0x16 },
- { 0x09, 0x00 },
- { 0x0a, 0x01 },
- { 0x0b, 0x03 },
- { 0x16, 0xb7 },
- { 0x17, 0x0a },
- { 0x18, 0x20 },
- { 0x19, 0x2a },
- { 0x1a, 0x6a },
- { 0x1b, 0x8a },
- { 0x1c, 0x00 },
- { 0x1d, 0x85 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x06 },
- { 0x5c, 0x0b },
- { 0x5d, 0x10 },
- { 0x5e, 0x16 }
- }
- },
- { { 150 }, 4350, 2, {
- { 0x08, 0x16 },
- { 0x09, 0x00 },
- { 0x0a, 0x01 },
- { 0x0b, 0x03 },
- { 0x16, 0xb7 },
- { 0x17, 0x0a },
- { 0x18, 0x20 },
- { 0x19, 0x2a },
- { 0x1a, 0x6a },
- { 0x1b, 0x8a },
- { 0x1c, 0x00 },
- { 0x1d, 0x85 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x06 },
- { 0x5c, 0x0b },
- { 0x5d, 0x10 },
- { 0x5e, 0x16 }
- }
- },
- { { 300 }, 4350, 2, {
- { 0x08, 0x16 },
- { 0x09, 0x00 },
- { 0x0a, 0x01 },
- { 0x0b, 0x03 },
- { 0x16, 0xb7 },
- { 0x17, 0x0a },
- { 0x18, 0x20 },
- { 0x19, 0x2a },
- { 0x1a, 0x6a },
- { 0x1b, 0x8a },
- { 0x1c, 0x00 },
- { 0x1d, 0x85 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x06 },
- { 0x5c, 0x0b },
- { 0x5d, 0x10 },
- { 0x5e, 0x16 }
- }
- },
- { { 600 }, 8700, 1, {
- { 0x08, 0x01 },
- { 0x09, 0x03 },
- { 0x0a, 0x04 },
- { 0x0b, 0x06 },
- { 0x16, 0xb7 },
- { 0x17, 0x0a },
- { 0x18, 0x20 },
- { 0x19, 0x2a },
- { 0x1a, 0x6a },
- { 0x1b, 0x8a },
- { 0x1c, 0x00 },
- { 0x1d, 0x05 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x06 },
- { 0x5c, 0x0b },
- { 0x5d, 0x10 },
- { 0x5e, 0x16 }
+ { { 75 }, 300, 150, 4480, Ratio{1, 2}, 2, {
+ { 0x08, 0x16 }, { 0x09, 0x00 }, { 0x0a, 0x01 }, { 0x0b, 0x03 },
+ { 0x16, 0xb7 }, { 0x17, 0x0a }, { 0x18, 0x20 }, { 0x19, 0x2a },
+ { 0x1a, 0x6a }, { 0x1b, 0x8a }, { 0x1c, 0x00 }, { 0x1d, 0x85 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x06 }, { 0x5c, 0x0b }, { 0x5d, 0x10 }, { 0x5e, 0x16 }
+ }
+ },
+ { { 150 }, 300, 300, 4350, Ratio{1, 2}, 5, {
+ { 0x08, 0x16 }, { 0x09, 0x00 }, { 0x0a, 0x01 }, { 0x0b, 0x03 },
+ { 0x16, 0xb7 }, { 0x17, 0x0a }, { 0x18, 0x20 }, { 0x19, 0x2a },
+ { 0x1a, 0x6a }, { 0x1b, 0x8a }, { 0x1c, 0x00 }, { 0x1d, 0x85 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x06 }, { 0x5c, 0x0b }, { 0x5d, 0x10 }, { 0x5e, 0x16 }
+ }
+ },
+ { { 300 }, 300, 600, 4350, Ratio{1, 2}, 10, {
+ { 0x08, 0x16 }, { 0x09, 0x00 }, { 0x0a, 0x01 }, { 0x0b, 0x03 },
+ { 0x16, 0xb7 }, { 0x17, 0x0a }, { 0x18, 0x20 }, { 0x19, 0x2a },
+ { 0x1a, 0x6a }, { 0x1b, 0x8a }, { 0x1c, 0x00 }, { 0x1d, 0x85 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x06 }, { 0x5c, 0x0b }, { 0x5d, 0x10 }, { 0x5e, 0x16 }
+ }
+ },
+ { { 600 }, 600, 600, 8700, Ratio{1, 1}, 20, {
+ { 0x08, 0x01 }, { 0x09, 0x03 }, { 0x0a, 0x04 }, { 0x0b, 0x06 },
+ { 0x16, 0xb7 }, { 0x17, 0x0a }, { 0x18, 0x20 }, { 0x19, 0x2a },
+ { 0x1a, 0x6a }, { 0x1b, 0x8a }, { 0x1c, 0x00 }, { 0x1d, 0x05 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x06 }, { 0x5c, 0x0b }, { 0x5d, 0x10 }, { 0x5e, 0x16 }
}
},
};
@@ -973,8 +456,11 @@ void genesys_init_sensor_tables()
for (const CustomSensorSettings& setting : custom_settings)
{
sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpiset = setting.register_dpiset;
sensor.exposure_lperiod = setting.exposure_lperiod;
- sensor.ccd_size_divisor = setting.ccd_size_divisor;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
sensor.custom_regs = setting.custom_regs;
s_sensors->push_back(sensor);
}
@@ -982,399 +468,300 @@ void genesys_init_sensor_tables()
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CIS_CANON_LIDE_35;
- sensor.optical_res = 1200;
- sensor.ccd_size_divisor = 2;
+ sensor.sensor_id = SensorId::CIS_CANON_LIDE_35; // gl841
+ sensor.full_resolution = 1200;
+ sensor.register_dpihw = 1200;
sensor.black_pixels = 87;
sensor.dummy_pixel = 87;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10400;
sensor.fau_gain_white_ref = 0;
sensor.gain_white_ref = 0;
sensor.exposure = { 0x0400, 0x0400, 0x0400 };
sensor.custom_regs = {
- { 0x08, 0x00 },
- { 0x09, 0x00 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0x00 },
- { 0x17, 0x02 },
- { 0x18, 0x00 },
- { 0x19, 0x50 },
- { 0x1a, 0x00 }, // TODO: 1a-1d: these do no harm, but may be neccessery for CCD
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x02 },
- { 0x52, 0x05 }, // [GB](HI|LOW) not needed for cis
- { 0x53, 0x07 },
- { 0x54, 0x00 },
- { 0x55, 0x00 },
- { 0x56, 0x00 },
- { 0x57, 0x00 },
- { 0x58, 0x3a },
- { 0x59, 0x03 },
- { 0x5a, 0x40 },
- { 0x5b, 0x00 }, // TODO: 5b-5e
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 },
+ { 0x16, 0x00 }, { 0x17, 0x02 }, { 0x18, 0x00 }, { 0x19, 0x50 },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x02 },
+ { 0x52, 0x05 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x3a }, { 0x59, 0x03 }, { 0x5a, 0x40 },
+ { 0x70, 0x00 }, { 0x71, 0x00 }, { 0x72, 0x00 }, { 0x73, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpiset;
+ unsigned shading_resolution;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 600, 150, 600, 11 },
+ { { 100 }, 600, 200, 600, 14 },
+ { { 150 }, 600, 300, 600, 22 },
+ { { 200 }, 600, 400, 600, 29 },
+ { { 300 }, 600, 600, 600, 44 },
+ { { 600 }, 600, 1200, 600, 88 },
+ { { 1200 }, 1200, 1200, 1200, 88 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.shading_resolution;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CIS_XP200;
- sensor.optical_res = 600;
+ sensor.sensor_id = SensorId::CIS_CANON_LIDE_60; // gl841
+ sensor.full_resolution = 1200;
+ sensor.register_dpihw = 1200;
+ sensor.black_pixels = 87;
+ sensor.dummy_pixel = 87;
+ sensor.fau_gain_white_ref = 0;
+ sensor.gain_white_ref = 0;
+ sensor.exposure = { 0x0400, 0x0400, 0x0400 };
+ sensor.custom_regs = {
+ { 0x16, 0x00 }, { 0x17, 0x01 }, { 0x18, 0x00 }, { 0x19, 0x50 },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x02 },
+ { 0x52, 0x05 }, { 0x53, 0x07 }, { 0x54, 0x03 }, { 0x55, 0x05 },
+ { 0x56, 0x02 }, { 0x57, 0x05 }, { 0x58, 0x3a }, { 0x59, 0x03 }, { 0x5a, 0x40 },
+ { 0x70, 0x00 }, { 0x71, 0x00 }, { 0x72, 0x00 }, { 0x73, 0x00 },
+ };
+ sensor.gamma = { 1.0f, 1.0f, 1.0f };
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpiset;
+ unsigned shading_resolution;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 600, 150, 600, 11 },
+ { { 100 }, 600, 200, 600, 14 },
+ { { 150 }, 600, 300, 600, 22 },
+ { { 200 }, 600, 400, 600, 29 },
+ { { 300 }, 600, 600, 600, 44 },
+ { { 600 }, 600, 1200, 600, 88 },
+ { { 1200 }, 1200, 1200, 1200, 88 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.shading_resolution;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
+
+
+ sensor = Genesys_Sensor();
+ sensor.sensor_id = SensorId::CIS_CANON_LIDE_90; // gl842
+ sensor.full_resolution = 2400;
+ sensor.black_pixels = 20;
+ sensor.dummy_pixel = 253;
+ sensor.fau_gain_white_ref = 150;
+ sensor.gain_white_ref = 150;
+ sensor.use_host_side_calib = true;
+ sensor.custom_regs = {
+ { 0x16, 0x20 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0xff },
+ { 0x1a, 0x24 }, { 0x1c, 0x00 }, { 0x1d, 0x04 },
+ { 0x52, 0x02 }, { 0x53, 0x04 }, { 0x54, 0x02 }, { 0x55, 0x04 },
+ { 0x56, 0x02 }, { 0x57, 0x04 }, { 0x58, 0x0a }, { 0x59, 0x71 }, { 0x5a, 0x55 },
+ { 0x70, 0x00 }, { 0x71, 0x05 }, { 0x72, 0x07 }, { 0x73, 0x09 },
+ { 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x3f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x1e }, { 0x7d, 0x11 }, { 0x7f, 0x50 }
+ };
+ sensor.gamma = { 1.0f, 1.0f, 1.0f };
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpihw;
+ unsigned register_dpiset;
+ unsigned shading_resolution;
+ unsigned shading_factor;
+ int output_pixel_offset;
+ SensorExposure exposure;
+ unsigned exposure_lperiod;
+ unsigned segment_size;
+ std::vector<unsigned> segment_order;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 300 }, 300, 600, 600, 300, 2, 280, { 955, 1235, 675 }, 6500, 5152,
+ std::vector<unsigned>{} },
+ { { 600 }, 600, 600, 600, 600, 1, 250, { 1655, 2075, 1095 }, 6536, 5152,
+ std::vector<unsigned>{} },
+ { { 1200 }, 1200, 1200, 1200, 1200, 1, 500, { 3055, 4175, 1935 }, 12688, 5152,
+ {0, 1} },
+ { { 2400 }, 2400, 2400, 2400, 2400, 1, 1000, { 5855, 7535, 3615 }, 21500, 5152,
+ {0, 1, 2, 3} },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.shading_resolution;
+ sensor.shading_factor = setting.shading_factor;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.exposure = setting.exposure;
+ sensor.exposure_lperiod = setting.exposure_lperiod;
+ sensor.segment_size = setting.segment_size;
+ sensor.segment_order = setting.segment_order;
+ s_sensors->push_back(sensor);
+ }
+ }
+
+
+ sensor = Genesys_Sensor();
+ sensor.sensor_id = SensorId::CIS_XP200; // gl646
+ sensor.full_resolution = 600;
sensor.black_pixels = 5;
sensor.dummy_pixel = 38;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 5200;
sensor.fau_gain_white_ref = 200;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x1450, 0x0c80, 0x0a28 };
- sensor.custom_base_regs = {
- { 0x08, 0x16 },
- { 0x09, 0x00 },
- { 0x0a, 0x01 },
- { 0x0b, 0x03 },
- { 0x16, 0xb7 },
- { 0x17, 0x0a },
- { 0x18, 0x20 },
- { 0x19, 0x2a },
- { 0x1a, 0x6a },
- { 0x1b, 0x8a },
- { 0x1c, 0x00 },
- { 0x1d, 0x05 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x06 },
- { 0x5c, 0x0b },
- { 0x5d, 0x10 },
- { 0x5e, 0x16 },
- };
sensor.custom_regs = {
- { 0x08, 0x06 },
- { 0x09, 0x07 },
- { 0x0a, 0x0a },
- { 0x0b, 0x04 },
- { 0x16, 0x24 },
- { 0x17, 0x04 },
- { 0x18, 0x00 },
- { 0x19, 0x2a },
- { 0x1a, 0x0a },
- { 0x1b, 0x0a },
- { 0x1c, 0x00 },
- { 0x1d, 0x11 },
- { 0x52, 0x08 },
- { 0x53, 0x02 },
- { 0x54, 0x00 },
- { 0x55, 0x00 },
- { 0x56, 0x00 },
- { 0x57, 0x00 },
- { 0x58, 0x1a },
- { 0x59, 0x51 },
- { 0x5a, 0x00 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
+ { 0x08, 0x06 }, { 0x09, 0x07 }, { 0x0a, 0x0a }, { 0x0b, 0x04 },
+ { 0x16, 0x24 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x2a },
+ { 0x1a, 0x0a }, { 0x1b, 0x0a }, { 0x1c, 0x00 }, { 0x1d, 0x11 },
+ { 0x52, 0x08 }, { 0x53, 0x02 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x1a }, { 0x59, 0x51 }, { 0x5a, 0x00 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
};
sensor.gamma = { 2.1f, 2.1f, 2.1f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
std::vector<unsigned> channels;
unsigned exposure_lperiod;
SensorExposure exposure;
+ int output_pixel_offset;
};
CustomSensorSettings custom_settings[] = {
- { { 75 }, { 3 }, 5700, { 0x1644, 0x0c80, 0x092e } },
- { { 100 }, { 3 }, 5700, { 0x1644, 0x0c80, 0x092e } },
- { { 200 }, { 3 }, 5700, { 0x1644, 0x0c80, 0x092e } },
- { { 300 }, { 3 }, 9000, { 0x1644, 0x0c80, 0x092e } },
- { { 600 }, { 3 }, 16000, { 0x1644, 0x0c80, 0x092e } },
- { { 75 }, { 1 }, 16000, { 0x050a, 0x0fa0, 0x1010 } },
- { { 100 }, { 1 }, 7800, { 0x050a, 0x0fa0, 0x1010 } },
- { { 200 }, { 1 }, 11000, { 0x050a, 0x0fa0, 0x1010 } },
- { { 300 }, { 1 }, 13000, { 0x050a, 0x0fa0, 0x1010 } },
- { { 600 }, { 1 }, 24000, { 0x050a, 0x0fa0, 0x1010 } },
+ { { 75 }, { 3 }, 5700, { 0x1644, 0x0c80, 0x092e }, 4 },
+ { { 100 }, { 3 }, 5700, { 0x1644, 0x0c80, 0x092e }, 6 },
+ { { 200 }, { 3 }, 5700, { 0x1644, 0x0c80, 0x092e }, 12 },
+ { { 300 }, { 3 }, 9000, { 0x1644, 0x0c80, 0x092e }, 19 },
+ { { 600 }, { 3 }, 16000, { 0x1644, 0x0c80, 0x092e }, 38 },
+ { { 75 }, { 1 }, 16000, { 0x050a, 0x0fa0, 0x1010 }, 4 },
+ { { 100 }, { 1 }, 7800, { 0x050a, 0x0fa0, 0x1010 }, 6 },
+ { { 200 }, { 1 }, 11000, { 0x050a, 0x0fa0, 0x1010 }, 12 },
+ { { 300 }, { 1 }, 13000, { 0x050a, 0x0fa0, 0x1010 }, 19 },
+ { { 600 }, { 1 }, 24000, { 0x050a, 0x0fa0, 0x1010 }, 38 },
};
for (const CustomSensorSettings& setting : custom_settings)
{
sensor.resolutions = setting.resolutions;
sensor.channels = setting.channels;
+ sensor.register_dpiset = setting.resolutions.values()[0];
sensor.exposure_lperiod = setting.exposure_lperiod;
sensor.exposure = setting.exposure;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
s_sensors->push_back(sensor);
}
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_HP3670;
- sensor.optical_res = 1200;
+ sensor.sensor_id = SensorId::CCD_HP3670; // gl646
+ sensor.full_resolution = 1200;
sensor.black_pixels = 48;
sensor.dummy_pixel = 16;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10872;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0, 0, 0 };
- sensor.stagger_config = StaggerConfig{1200, 4}; // FIXME: may be incorrect
- sensor.custom_base_regs = {
- { 0x08, 0x00 },
- { 0x09, 0x0a },
- { 0x0a, 0x0b },
- { 0x0b, 0x0d },
- { 0x16, 0x33 },
- { 0x17, 0x07 },
- { 0x18, 0x20 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0xc0 },
- { 0x1d, 0x43 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x00 },
- { 0x5a, 0x15 },
- { 0x5b, 0x05 },
- { 0x5c, 0x0a },
- { 0x5d, 0x0f },
- { 0x5e, 0x00 },
- };
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
unsigned exposure_lperiod;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
+ StaggerConfig stagger_y;
GenesysRegisterSettingSet custom_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 50 }, 5758, {
- { 0x08, 0x00 },
- { 0x09, 0x0a },
- { 0x0a, 0x0b },
- { 0x0b, 0x0d },
- { 0x16, 0x33 },
- { 0x17, 0x07 },
- { 0x18, 0x33 },
- { 0x19, 0x2a },
- { 0x1a, 0x02 },
- { 0x1b, 0x13 },
- { 0x1c, 0xc0 },
- { 0x1d, 0x43 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x15 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x05 },
- { 0x5c, 0x0a },
- { 0x5d, 0x0f },
- { 0x5e, 0x00 }
- }
- },
- { { 75 }, 4879, {
- { 0x08, 0x00 },
- { 0x09, 0x0a },
- { 0x0a, 0x0b },
- { 0x0b, 0x0d },
- { 0x16, 0x33 },
- { 0x17, 0x07 },
- { 0x18, 0x33 },
- { 0x19, 0x2a },
- { 0x1a, 0x02 },
- { 0x1b, 0x13 },
- { 0x1c, 0xc0 },
- { 0x1d, 0x43 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x15 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x05 },
- { 0x5c, 0x0a },
- { 0x5d, 0x0f },
- { 0x5e, 0x00 }
- }
- },
- { { 100 }, 4487, {
- { 0x08, 0x00 },
- { 0x09, 0x0a },
- { 0x0a, 0x0b },
- { 0x0b, 0x0d },
- { 0x16, 0x33 },
- { 0x17, 0x07 },
- { 0x18, 0x33 },
- { 0x19, 0x2a },
- { 0x1a, 0x02 },
- { 0x1b, 0x13 },
- { 0x1c, 0xc0 },
- { 0x1d, 0x43 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x15 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x05 },
- { 0x5c, 0x0a },
- { 0x5d, 0x0f },
- { 0x5e, 0x00 }
- }
- },
- { { 150 }, 4879, {
- { 0x08, 0x00 },
- { 0x09, 0x0a },
- { 0x0a, 0x0b },
- { 0x0b, 0x0d },
- { 0x16, 0x33 },
- { 0x17, 0x07 },
- { 0x18, 0x33 },
- { 0x19, 0x2a },
- { 0x1a, 0x02 },
- { 0x1b, 0x13 },
- { 0x1c, 0xc0 },
- { 0x1d, 0x43 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x15 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x05 },
- { 0x5c, 0x0a },
- { 0x5d, 0x0f },
- { 0x5e, 0x00 }
- }
- },
- { { 300 }, 4503, {
- { 0x08, 0x00 },
- { 0x09, 0x0a },
- { 0x0a, 0x0b },
- { 0x0b, 0x0d },
- { 0x16, 0x33 },
- { 0x17, 0x07 },
- { 0x18, 0x33 },
- { 0x19, 0x2a },
- { 0x1a, 0x02 },
- { 0x1b, 0x13 },
- { 0x1c, 0xc0 },
- { 0x1d, 0x43 },
- { 0x52, 0x0f },
- { 0x53, 0x13 },
- { 0x54, 0x17 },
- { 0x55, 0x03 },
- { 0x56, 0x07 },
- { 0x57, 0x0b },
- { 0x58, 0x83 },
- { 0x59, 0x15 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x05 },
- { 0x5c, 0x0a },
- { 0x5d, 0x0f },
- { 0x5e, 0x00 }
- }
- },
- { { 600 }, 10251, {
- { 0x08, 0x00 },
- { 0x09, 0x05 },
- { 0x0a, 0x06 },
- { 0x0b, 0x08 },
- { 0x16, 0x33 },
- { 0x17, 0x07 },
- { 0x18, 0x31 },
- { 0x19, 0x2a },
- { 0x1a, 0x02 },
- { 0x1b, 0x0e },
- { 0x1c, 0xc0 },
- { 0x1d, 0x43 },
- { 0x52, 0x0b },
- { 0x53, 0x0f },
- { 0x54, 0x13 },
- { 0x55, 0x17 },
- { 0x56, 0x03 },
- { 0x57, 0x07 },
- { 0x58, 0x63 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x02 },
- { 0x5c, 0x0e },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
- }
- },
- { { 1200 }, 12750, {
- { 0x08, 0x0d },
- { 0x09, 0x0f },
- { 0x0a, 0x11 },
- { 0x0b, 0x13 },
- { 0x16, 0x2b },
- { 0x17, 0x07 },
- { 0x18, 0x30 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0xc0 },
- { 0x1d, 0x43 },
- { 0x52, 0x03 },
- { 0x53, 0x07 },
- { 0x54, 0x0b },
- { 0x55, 0x0f },
- { 0x56, 0x13 },
- { 0x57, 0x17 },
- { 0x58, 0x23 },
- { 0x59, 0x00 },
- { 0x5a, 0xc1 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x00 }
+ { { 50 }, 200, 5758, Ratio{1, 4}, 0, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x0a }, { 0x0a, 0x0b }, { 0x0b, 0x0d },
+ { 0x16, 0x33 }, { 0x17, 0x07 }, { 0x18, 0x33 }, { 0x19, 0x2a },
+ { 0x1a, 0x02 }, { 0x1b, 0x13 }, { 0x1c, 0xc0 }, { 0x1d, 0x43 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x15 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x05 }, { 0x5c, 0x0a }, { 0x5d, 0x0f }, { 0x5e, 0x00 }
+ }
+ },
+ { { 75 }, 300, 4879, Ratio{1, 4}, 1, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x0a }, { 0x0a, 0x0b }, { 0x0b, 0x0d },
+ { 0x16, 0x33 }, { 0x17, 0x07 }, { 0x18, 0x33 }, { 0x19, 0x2a },
+ { 0x1a, 0x02 }, { 0x1b, 0x13 }, { 0x1c, 0xc0 }, { 0x1d, 0x43 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x15 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x05 }, { 0x5c, 0x0a }, { 0x5d, 0x0f }, { 0x5e, 0x00 }
+ }
+ },
+ { { 100 }, 400, 4487, Ratio{1, 4}, 1, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x0a }, { 0x0a, 0x0b }, { 0x0b, 0x0d },
+ { 0x16, 0x33 }, { 0x17, 0x07 }, { 0x18, 0x33 }, { 0x19, 0x2a },
+ { 0x1a, 0x02 }, { 0x1b, 0x13 }, { 0x1c, 0xc0 }, { 0x1d, 0x43 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x15 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x05 }, { 0x5c, 0x0a }, { 0x5d, 0x0f }, { 0x5e, 0x00 }
+ }
+ },
+ { { 150 }, 600, 4879, Ratio{1, 4}, 2, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x0a }, { 0x0a, 0x0b }, { 0x0b, 0x0d },
+ { 0x16, 0x33 }, { 0x17, 0x07 }, { 0x18, 0x33 }, { 0x19, 0x2a },
+ { 0x1a, 0x02 }, { 0x1b, 0x13 }, { 0x1c, 0xc0 }, { 0x1d, 0x43 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x15 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x05 }, { 0x5c, 0x0a }, { 0x5d, 0x0f }, { 0x5e, 0x00 }
+ }
+ },
+ { { 300 }, 1200, 4503, Ratio{1, 4}, 4, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x0a }, { 0x0a, 0x0b }, { 0x0b, 0x0d },
+ { 0x16, 0x33 }, { 0x17, 0x07 }, { 0x18, 0x33 }, { 0x19, 0x2a },
+ { 0x1a, 0x02 }, { 0x1b, 0x13 }, { 0x1c, 0xc0 }, { 0x1d, 0x43 },
+ { 0x52, 0x0f }, { 0x53, 0x13 }, { 0x54, 0x17 }, { 0x55, 0x03 },
+ { 0x56, 0x07 }, { 0x57, 0x0b }, { 0x58, 0x83 }, { 0x59, 0x15 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x05 }, { 0x5c, 0x0a }, { 0x5d, 0x0f }, { 0x5e, 0x00 }
+ }
+ },
+ { { 600 }, 1200, 10251, Ratio{1, 2}, 8, StaggerConfig{}, {
+ { 0x08, 0x00 }, { 0x09, 0x05 }, { 0x0a, 0x06 }, { 0x0b, 0x08 },
+ { 0x16, 0x33 }, { 0x17, 0x07 }, { 0x18, 0x31 }, { 0x19, 0x2a },
+ { 0x1a, 0x02 }, { 0x1b, 0x0e }, { 0x1c, 0xc0 }, { 0x1d, 0x43 },
+ { 0x52, 0x0b }, { 0x53, 0x0f }, { 0x54, 0x13 }, { 0x55, 0x17 },
+ { 0x56, 0x03 }, { 0x57, 0x07 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x02 }, { 0x5c, 0x0e }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
+ }
+ },
+ { { 1200 }, 1200, 12750, Ratio{1, 1}, 16, StaggerConfig{4, 0}, {
+ { 0x08, 0x0d }, { 0x09, 0x0f }, { 0x0a, 0x11 }, { 0x0b, 0x13 },
+ { 0x16, 0x2b }, { 0x17, 0x07 }, { 0x18, 0x30 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0xc0 }, { 0x1d, 0x43 },
+ { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x0b }, { 0x55, 0x0f },
+ { 0x56, 0x13 }, { 0x57, 0x17 }, { 0x58, 0x23 }, { 0x59, 0x00 }, { 0x5a, 0xc1 },
+ { 0x5b, 0x00 }, { 0x5c, 0x00 }, { 0x5d, 0x00 }, { 0x5e, 0x00 }
}
},
};
@@ -1382,7 +769,11 @@ void genesys_init_sensor_tables()
for (const CustomSensorSettings& setting : custom_settings)
{
sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.register_dpiset;
sensor.exposure_lperiod = setting.exposure_lperiod;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.stagger_y = setting.stagger_y;
sensor.custom_regs = setting.custom_regs;
s_sensors->push_back(sensor);
}
@@ -1390,251 +781,278 @@ void genesys_init_sensor_tables()
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_DP665;
- sensor.optical_res = 600;
+ sensor.sensor_id = SensorId::CCD_DP665; // gl841
+ sensor.full_resolution = 600;
+ sensor.register_dpihw = 600;
+ sensor.shading_resolution = 600;
sensor.black_pixels = 27;
sensor.dummy_pixel = 27;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 2496;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x1100, 0x1100, 0x1100 };
sensor.custom_regs = {
- { 0x08, 0x00 },
- { 0x09, 0x00 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0x00 },
- { 0x17, 0x02 },
- { 0x18, 0x04 },
- { 0x19, 0x50 },
- { 0x1a, 0x10 },
- { 0x1b, 0x00 },
- { 0x1c, 0x20 },
- { 0x1d, 0x02 },
- { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis
- { 0x53, 0x05 },
- { 0x54, 0x00 },
- { 0x55, 0x00 },
- { 0x56, 0x00 },
- { 0x57, 0x00 },
- { 0x58, 0x54 },
- { 0x59, 0x03 },
- { 0x5a, 0x00 },
- { 0x5b, 0x00 }, // TODO: 5b-5e
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x01 },
+ { 0x16, 0x00 }, { 0x17, 0x02 }, { 0x18, 0x04 }, { 0x19, 0x50 },
+ { 0x1a, 0x10 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x02 },
+ { 0x52, 0x04 }, { 0x53, 0x05 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x54 }, { 0x59, 0x03 }, { 0x5a, 0x00 },
+ { 0x70, 0x00 }, { 0x71, 0x00 }, { 0x72, 0x00 }, { 0x73, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 75, 1 },
+ { { 150 }, 150, 3 },
+ { { 300 }, 300, 7 },
+ { { 600 }, 600, 14 },
+ { { 1200 }, 1200, 28 },
+ };
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_ROADWARRIOR;
- sensor.optical_res = 600;
+ sensor.sensor_id = SensorId::CCD_ROADWARRIOR; // gl841
+ sensor.full_resolution = 600;
+ sensor.register_dpihw = 600;
+ sensor.shading_resolution = 600;
sensor.black_pixels = 27;
sensor.dummy_pixel = 27;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 5200;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x1100, 0x1100, 0x1100 };
sensor.custom_regs = {
- { 0x08, 0x00 },
- { 0x09, 0x00 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0x00 },
- { 0x17, 0x02 },
- { 0x18, 0x04 },
- { 0x19, 0x50 },
- { 0x1a, 0x10 },
- { 0x1b, 0x00 },
- { 0x1c, 0x20 },
- { 0x1d, 0x02 },
- { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis
- { 0x53, 0x05 },
- { 0x54, 0x00 },
- { 0x55, 0x00 },
- { 0x56, 0x00 },
- { 0x57, 0x00 },
- { 0x58, 0x54 },
- { 0x59, 0x03 },
- { 0x5a, 0x00 },
- { 0x5b, 0x00 }, // TODO: 5b-5e
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x01 },
+ { 0x16, 0x00 }, { 0x17, 0x02 }, { 0x18, 0x04 }, { 0x19, 0x50 },
+ { 0x1a, 0x10 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x02 },
+ { 0x52, 0x04 }, { 0x53, 0x05 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x54 }, { 0x59, 0x03 }, { 0x5a, 0x00 },
+ { 0x70, 0x00 }, { 0x71, 0x00 }, { 0x72, 0x00 }, { 0x73, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 75, 1 },
+ { { 150 }, 150, 3 },
+ { { 300 }, 300, 7 },
+ { { 600 }, 600, 14 },
+ { { 1200 }, 1200, 28 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_DSMOBILE600;
- sensor.optical_res = 600;
+ sensor.sensor_id = SensorId::CCD_DSMOBILE600; // gl841
+ sensor.full_resolution = 600;
+ sensor.register_dpihw = 600;
+ sensor.shading_resolution = 600;
sensor.black_pixels = 28;
sensor.dummy_pixel = 28;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 5200;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x1544, 0x1544, 0x1544 };
sensor.custom_regs = {
- { 0x08, 0x00 },
- { 0x09, 0x00 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0x00 },
- { 0x17, 0x02 },
- { 0x18, 0x04 },
- { 0x19, 0x50 },
- { 0x1a, 0x10 },
- { 0x1b, 0x00 },
- { 0x1c, 0x20 },
- { 0x1d, 0x02 },
- { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis
- { 0x53, 0x05 },
- { 0x54, 0x00 },
- { 0x55, 0x00 },
- { 0x56, 0x00 },
- { 0x57, 0x00 },
- { 0x58, 0x54 },
- { 0x59, 0x03 },
- { 0x5a, 0x00 },
- { 0x5b, 0x00 }, // TODO: 5b-5e
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x01 },
+ { 0x16, 0x00 }, { 0x17, 0x02 }, { 0x18, 0x04 }, { 0x19, 0x50 },
+ { 0x1a, 0x10 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x02 },
+ { 0x52, 0x04 }, { 0x53, 0x05 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x54 }, { 0x59, 0x03 }, { 0x5a, 0x00 },
+ { 0x70, 0x00 }, { 0x71, 0x00 }, { 0x72, 0x00 }, { 0x73, 0x00 },
+ };
+ sensor.gamma = { 1.0f, 1.0f, 1.0f };
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 75, 3 },
+ { { 150 }, 150, 7 },
+ { { 300 }, 300, 14 },
+ { { 600 }, 600, 29 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
+
+
+ sensor = Genesys_Sensor();
+ sensor.sensor_id = SensorId::CCD_XP300; // gl841
+ sensor.full_resolution = 600;
+ sensor.register_dpihw = 1200; // FIXME: could be incorrect, but previous code used this value
+ sensor.shading_resolution = 600;
+ sensor.black_pixels = 27;
+ sensor.dummy_pixel = 27;
+ sensor.fau_gain_white_ref = 210;
+ sensor.gain_white_ref = 200;
+ sensor.exposure = { 0x1100, 0x1100, 0x1100 };
+ sensor.custom_regs = {
+ { 0x16, 0x00 }, { 0x17, 0x02 }, { 0x18, 0x04 }, { 0x19, 0x50 },
+ { 0x1a, 0x10 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x02 },
+ { 0x52, 0x04 }, { 0x53, 0x05 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x54 }, { 0x59, 0x03 }, { 0x5a, 0x00 },
+ { 0x70, 0x00 }, { 0x71, 0x00 }, { 0x72, 0x00 }, { 0x73, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 150, 3 },
+ { { 150 }, 300, 7 },
+ { { 300 }, 600, 14 },
+ { { 600 }, 1200, 28 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_XP300;
- sensor.optical_res = 600;
+ sensor.sensor_id = SensorId::CCD_DOCKETPORT_487; // gl841
+ sensor.full_resolution = 600;
+ sensor.register_dpihw = 600;
+ sensor.shading_resolution = 600;
sensor.black_pixels = 27;
sensor.dummy_pixel = 27;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10240;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x1100, 0x1100, 0x1100 };
sensor.custom_regs = {
- { 0x08, 0x00 },
- { 0x09, 0x00 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0x00 },
- { 0x17, 0x02 },
- { 0x18, 0x04 },
- { 0x19, 0x50 },
- { 0x1a, 0x10 },
- { 0x1b, 0x00 },
- { 0x1c, 0x20 },
- { 0x1d, 0x02 },
- { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis
- { 0x53, 0x05 },
- { 0x54, 0x00 },
- { 0x55, 0x00 },
- { 0x56, 0x00 },
- { 0x57, 0x00 },
- { 0x58, 0x54 },
- { 0x59, 0x03 },
- { 0x5a, 0x00 },
- { 0x5b, 0x00 }, // TODO: 5b-5e
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x01 },
+ { 0x16, 0x00 }, { 0x17, 0x02 }, { 0x18, 0x04 }, { 0x19, 0x50 },
+ { 0x1a, 0x10 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x02 },
+ { 0x52, 0x04 }, { 0x53, 0x05 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x54 }, { 0x59, 0x03 }, { 0x5a, 0x00 },
+ { 0x70, 0x00 }, { 0x71, 0x00 }, { 0x72, 0x00 }, { 0x73, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 150, 3 },
+ { { 150 }, 300, 7 },
+ { { 300 }, 600, 14 },
+ { { 600 }, 600, 28 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_DP685;
- sensor.optical_res = 600;
+ sensor.sensor_id = SensorId::CCD_DP685; // gl841
+ sensor.full_resolution = 600;
+ sensor.register_dpihw = 600;
+ sensor.shading_resolution = 600;
+ sensor.full_resolution = 600;
sensor.black_pixels = 27;
sensor.dummy_pixel = 27;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 5020;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x1100, 0x1100, 0x1100 };
sensor.custom_regs = {
- { 0x08, 0x00 },
- { 0x09, 0x00 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0x00 },
- { 0x17, 0x02 },
- { 0x18, 0x04 },
- { 0x19, 0x50 },
- { 0x1a, 0x10 },
- { 0x1b, 0x00 },
- { 0x1c, 0x20 },
- { 0x1d, 0x02 },
- { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis
- { 0x53, 0x05 },
- { 0x54, 0x00 },
- { 0x55, 0x00 },
- { 0x56, 0x00 },
- { 0x57, 0x00 },
- { 0x58, 0x54 },
- { 0x59, 0x03 },
- { 0x5a, 0x00 },
- { 0x5b, 0x00 }, // TODO: 5b-5e
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x01 },
+ { 0x16, 0x00 }, { 0x17, 0x02 }, { 0x18, 0x04 }, { 0x19, 0x50 },
+ { 0x1a, 0x10 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x02 },
+ { 0x52, 0x04 }, { 0x53, 0x05 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x54 }, { 0x59, 0x03 }, { 0x5a, 0x00 },
+ { 0x70, 0x00 }, { 0x71, 0x00 }, { 0x72, 0x00 }, { 0x73, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 75, 3 },
+ { { 150 }, 150, 6 },
+ { { 300 }, 300, 13 },
+ { { 600 }, 600, 27 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CIS_CANON_LIDE_200;
- sensor.optical_res = 4800;
+ sensor.sensor_id = SensorId::CIS_CANON_LIDE_200; // gl847
+ sensor.full_resolution = 4800;
sensor.black_pixels = 87*4;
sensor.dummy_pixel = 16*4;
- sensor.ccd_start_xoffset = 320*8;
- sensor.sensor_pixels = 5136*8;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
sensor.gamma = { 2.2f, 2.2f, 2.2f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpihw;
int exposure_lperiod;
SensorExposure exposure;
+ Ratio pixel_count_ratio;
+ unsigned shading_factor;
+ int output_pixel_offset;
unsigned segment_size;
std::vector<unsigned> segment_order;
GenesysRegisterSettingSet custom_regs;
@@ -1642,7 +1060,44 @@ void genesys_init_sensor_tables()
CustomSensorSettings custom_settings[] = {
// Note: Windows driver uses 1424 lperiod and enables dummy line (0x17)
- { { 75, 100, 150, 200 }, 2848, { 304, 203, 180 }, 5136, std::vector<unsigned>{}, {
+ { { 75 }, 600, 2848, { 304, 203, 180 }, Ratio{1, 8}, 8, 40, 5136,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
+ { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
+ { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ }
+ },
+ // Note: Windows driver uses 1424 lperiod and enables dummy line (0x17)
+ { { 100 }, 600, 2848, { 304, 203, 180 }, Ratio{1, 8}, 6, 53, 5136,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
+ { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
+ { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ }
+ },
+ // Note: Windows driver uses 1424 lperiod and enables dummy line (0x17)
+ { { 150 }, 600, 2848, { 304, 203, 180 }, Ratio{1, 8}, 4, 80, 5136,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
+ { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
+ { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ }
+ },
+ // Note: Windows driver uses 1424 lperiod and enables dummy line (0x17)
+ { { 200 }, 600, 2848, { 304, 203, 180 }, Ratio{1, 8}, 3, 106, 5136,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1653,7 +1108,8 @@ void genesys_init_sensor_tables()
}
},
// Note: Windows driver uses 788 lperiod and enables dummy line (0x17)
- { { 300, 400 }, 1424, { 304, 203, 180 }, 5136, std::vector<unsigned>{}, {
+ { { 300 }, 600, 1424, { 304, 203, 180 }, Ratio{1, 8}, 2, 160, 5136,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1663,7 +1119,9 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 600 }, 1432, { 492, 326, 296 }, 5136, std::vector<unsigned>{}, {
+ // Note: Windows driver uses 788 lperiod and enables dummy line (0x17)
+ { { 400 }, 600, 1424, { 304, 203, 180 }, Ratio{1, 8}, 1, 213, 5136,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1673,7 +1131,19 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 1200 }, 2712, { 935, 592, 538 }, 5136, { 0, 1 }, {
+ { { 600 }, 600, 1432, { 492, 326, 296 }, Ratio{1, 8}, 1, 320, 5136,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
+ { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
+ { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ }
+ },
+ { { 1200 }, 1200, 2712, { 935, 592, 538 }, Ratio{1, 8}, 1, 640, 5136,
+ { 0, 1 }, {
{ 0x16, 0x10 }, { 0x17, 0x08 }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1683,7 +1153,8 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 2400 }, 5280, { 1777, 1125, 979 }, 5136, { 0, 2, 1, 3 }, {
+ { { 2400 }, 2400, 5280, { 1777, 1125, 979 }, Ratio{1, 8}, 1, 1280, 5136,
+ { 0, 2, 1, 3 }, {
{ 0x16, 0x10 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1693,7 +1164,8 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 4800 }, 10416, { 3377, 2138, 1780 }, 5136, { 0, 2, 4, 6, 1, 3, 5, 7 }, {
+ { { 4800 }, 4800, 10416, { 3377, 2138, 1780 }, Ratio{1, 8}, 1, 2560, 5136,
+ { 0, 2, 4, 6, 1, 3, 5, 7 }, {
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1707,8 +1179,14 @@ void genesys_init_sensor_tables()
for (const auto& setting : custom_settings) {
sensor.resolutions = setting.resolutions;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.resolutions.values()[0];
+ sensor.shading_resolution = setting.register_dpihw;
sensor.exposure_lperiod = setting.exposure_lperiod;
sensor.exposure = setting.exposure;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.shading_factor = setting.shading_factor;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
sensor.segment_size = setting.segment_size;
sensor.segment_order = setting.segment_order;
sensor.custom_regs = setting.custom_regs;
@@ -1718,34 +1196,64 @@ void genesys_init_sensor_tables()
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CIS_CANON_LIDE_700F;
- sensor.optical_res = 4800;
+ sensor.sensor_id = SensorId::CIS_CANON_LIDE_700F; // gl847
+ sensor.full_resolution = 4800;
sensor.black_pixels = 73*8; // black pixels 73 at 600 dpi
sensor.dummy_pixel = 16*8;
- // 384 at 600 dpi
- sensor.ccd_start_xoffset = 384*8;
- // 8x5570 segments, 5187+1 for rounding
- sensor.sensor_pixels = 5188*8;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpihw;
int exposure_lperiod;
SensorExposure exposure;
+ Ratio pixel_count_ratio;
+ unsigned shading_factor;
+ int output_pixel_offset;
unsigned segment_size;
std::vector<unsigned> segment_order;
GenesysRegisterSettingSet custom_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 75, 100, 150, 200 }, 2848, { 465, 310, 239 }, 5187, std::vector<unsigned>{}, {
+ { { 75 }, 600, 2848, { 465, 310, 239 }, Ratio{1, 8}, 8, 48, 5187,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0xff },
+ { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
+ { 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x87 },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0xf9 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ }
+ },
+ { { 100 }, 600, 2848, { 465, 310, 239 }, Ratio{1, 8}, 6, 64, 5187,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0xff },
+ { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
+ { 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x87 },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0xf9 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ }
+ },
+ { { 150 }, 600, 2848, { 465, 310, 239 }, Ratio{1, 8}, 4, 96, 5187,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0xff },
+ { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
+ { 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x87 },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0xf9 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ }
+ },
+ { { 200 }, 600, 2848, { 465, 310, 239 }, Ratio{1, 8}, 3, 128, 5187,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1755,7 +1263,8 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 300 }, 1424, { 465, 310, 239 }, 5187, std::vector<unsigned>{}, {
+ { { 300 }, 600, 1424, { 465, 310, 239 }, Ratio{1, 8}, 2, 192, 5187,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1765,7 +1274,8 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 600 }, 1504, { 465, 310, 239 }, 5187, std::vector<unsigned>{}, {
+ { { 600 }, 600, 1504, { 465, 310, 239 }, Ratio{1, 8}, 1, 384, 5187,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1775,7 +1285,8 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 1200 }, 2696, { 1464, 844, 555 }, 5187, { 0, 1 }, {
+ { { 1200 }, 1200, 2696, { 1464, 844, 555 }, Ratio{1, 8}, 1, 768, 5187,
+ { 0, 1 }, {
{ 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1785,7 +1296,8 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 2400 }, 10576, { 2798, 1558, 972 }, 5187, { 0, 1, 2, 3 }, {
+ { { 2400 }, 2400, 10576, { 2798, 1558, 972 }, Ratio{1, 8}, 1, 1536, 5187,
+ { 0, 1, 2, 3 }, {
{ 0x16, 0x10 }, { 0x17, 0x08 }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1795,7 +1307,8 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 4800 }, 10576, { 2798, 1558, 972 }, 5187, { 0, 1, 4, 5, 2, 3, 6, 7 }, {
+ { { 4800 }, 4800, 10576, { 2798, 1558, 972 }, Ratio{1, 8}, 1, 3072, 5187,
+ { 0, 1, 4, 5, 2, 3, 6, 7 }, {
{ 0x16, 0x10 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1809,8 +1322,14 @@ void genesys_init_sensor_tables()
for (const auto& setting : custom_settings) {
sensor.resolutions = setting.resolutions;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.resolutions.values()[0];
+ sensor.shading_resolution = setting.register_dpihw;
sensor.exposure_lperiod = setting.exposure_lperiod;
sensor.exposure = setting.exposure;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.shading_factor = setting.shading_factor;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
sensor.segment_size = setting.segment_size;
sensor.segment_order = setting.segment_order;
sensor.custom_regs = setting.custom_regs;
@@ -1820,33 +1339,32 @@ void genesys_init_sensor_tables()
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CIS_CANON_LIDE_100;
- sensor.optical_res = 2400;
+ sensor.sensor_id = SensorId::CIS_CANON_LIDE_100; // gl847
+ sensor.full_resolution = 2400;
sensor.black_pixels = 87*4;
sensor.dummy_pixel = 16*4;
- sensor.ccd_start_xoffset = 320*4;
- sensor.sensor_pixels = 5136*4;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x01c1, 0x0126, 0x00e5 };
sensor.gamma = { 2.2f, 2.2f, 2.2f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpihw;
int exposure_lperiod;
SensorExposure exposure;
+ Ratio pixel_count_ratio;
+ unsigned shading_factor;
+ int output_pixel_offset;
unsigned segment_size;
std::vector<unsigned> segment_order;
GenesysRegisterSettingSet custom_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 75, 100, 150, 200 }, 2304, { 423, 294, 242 }, 5136, std::vector<unsigned>{}, {
+ { { 75 }, 600, 2304, { 423, 294, 242 }, Ratio{1, 4}, 8, 40, 5136,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1856,7 +1374,8 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 300 }, 1728, { 423, 294, 242 }, 5136, std::vector<unsigned>{}, {
+ { { 100 }, 600, 2304, { 423, 294, 242 }, Ratio{1, 4}, 6, 53, 5136,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1866,7 +1385,41 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 600 }, 1432, { 423, 294, 242 }, 5136, std::vector<unsigned>{}, {
+ { { 150 }, 600, 2304, { 423, 294, 242 }, Ratio{1, 4}, 4, 80, 5136,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
+ { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
+ { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ }
+ },
+ { { 200 }, 600, 2304, { 423, 294, 242 }, Ratio{1, 4}, 3, 106, 5136,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
+ { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
+ { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ }
+ },
+ { { 300 }, 600, 1728, { 423, 294, 242 }, Ratio{1, 4}, 2, 160, 5136,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
+ { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
+ { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ }
+ },
+ { { 600 }, 600, 1432, { 423, 294, 242 }, Ratio{1, 4}, 1, 320, 5136,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1876,7 +1429,7 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
},
},
- { { 1200 }, 2712, { 791, 542, 403 }, 5136, {0, 1}, {
+ { { 1200 }, 1200, 2712, { 791, 542, 403 }, Ratio{1, 4}, 1, 640, 5136, {0, 1}, {
{ 0x16, 0x10 }, { 0x17, 0x08 }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1886,7 +1439,7 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
}
},
- { { 2400 }, 5280, { 1504, 1030, 766 }, 5136, {0, 2, 1, 3}, {
+ { { 2400 }, 2400, 5280, { 1504, 1030, 766 }, Ratio{1, 4}, 1, 1280, 5136, {0, 2, 1, 3}, {
{ 0x16, 0x10 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0xff },
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 },
{ 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
@@ -1900,8 +1453,14 @@ void genesys_init_sensor_tables()
for (const auto& setting : custom_settings) {
sensor.resolutions = setting.resolutions;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.resolutions.values()[0];
+ sensor.shading_resolution = setting.register_dpihw;
sensor.exposure_lperiod = setting.exposure_lperiod;
sensor.exposure = setting.exposure;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.shading_factor = setting.shading_factor;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
sensor.segment_size = setting.segment_size;
sensor.segment_order = setting.segment_order;
sensor.custom_regs = setting.custom_regs;
@@ -1910,12 +1469,12 @@ void genesys_init_sensor_tables()
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_KVSS080;
- sensor.optical_res = 600;
+ sensor.sensor_id = SensorId::CCD_KVSS080; // gl843
+ sensor.full_resolution = 600;
+ sensor.register_dpihw = 600;
+ sensor.shading_resolution = 600;
sensor.black_pixels = 38;
sensor.dummy_pixel = 38;
- sensor.ccd_start_xoffset = 152;
- sensor.sensor_pixels = 5376;
sensor.fau_gain_white_ref = 160;
sensor.gain_white_ref = 160;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
@@ -1946,191 +1505,170 @@ void genesys_init_sensor_tables()
{ 0x58, 0x6b },
{ 0x59, 0x00 },
{ 0x5a, 0xc0 },
+ { 0x7d, 0x90 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
+ };
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 75, Ratio{1, 1}, 4 },
+ { { 100 }, 100, Ratio{1, 1}, 6 },
+ { { 150 }, 150, Ratio{1, 1}, 9 },
+ { { 200 }, 200, Ratio{1, 1}, 12 },
+ { { 300 }, 300, Ratio{1, 1}, 19 },
+ { { 600 }, 600, Ratio{1, 1}, 38 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_G4050;
- sensor.optical_res = 4800;
+ sensor.sensor_id = SensorId::CCD_G4050; // gl843
+ sensor.full_resolution = 4800;
sensor.black_pixels = 50*8;
// 31 at 600 dpi dummy_pixels 58 at 1200
sensor.dummy_pixel = 58;
- sensor.ccd_start_xoffset = 152;
- sensor.sensor_pixels = 5360*8;
sensor.fau_gain_white_ref = 160;
sensor.gain_white_ref = 160;
sensor.exposure = { 0x2c09, 0x22b8, 0x10f0 };
- sensor.stagger_config = StaggerConfig{ 2400, 4 }; // FIXME: may be incorrect
sensor.custom_regs = {};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpihw;
+ unsigned register_dpiset;
int exposure_lperiod;
ScanMethod method;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
+ StaggerConfig stagger_y; // FIXME: may be incorrect
GenesysRegisterSettingSet extra_custom_regs;
};
+ GenesysRegisterSettingSet regs_100_to_600 = {
+ { 0x0c, 0x00 },
+ { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x08 },
+ { 0x52, 0x0b }, { 0x53, 0x0e }, { 0x54, 0x11 }, { 0x55, 0x02 }, { 0x56, 0x05 },
+ { 0x57, 0x08 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x00 }, { 0x71, 0x02 },
+ { 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff },
+ { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff },
+ { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, { 0x7d, 0x90 },
+ { 0x9e, 0x00 },
+ { 0xaa, 0x00 },
+ };
+
+ GenesysRegisterSettingSet regs_1200 = {
+ { 0x0c, 0x20 },
+ { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0x00 }, { 0x1d, 0x08 },
+ { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b }, { 0x56, 0x0e },
+ { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x08 }, { 0x71, 0x0c },
+ { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
+ { 0x77, 0x00 }, { 0x78, 0x01 }, { 0x79, 0xff },
+ { 0x7a, 0x00 }, { 0x7b, 0x01 }, { 0x7c, 0xff }, { 0x7d, 0x90 },
+ { 0x9e, 0xc0 },
+ { 0xaa, 0x05 },
+ };
+
+ GenesysRegisterSettingSet regs_2400 = {
+ { 0x0c, 0x20 },
+ { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0xc0 }, { 0x1d, 0x08 },
+ { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b }, { 0x56, 0x0e },
+ { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x08 }, { 0x71, 0x0a },
+ { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, { 0x7d, 0x90 },
+ { 0x9e, 0xc0 },
+ { 0xaa, 0x05 },
+ };
+
+ GenesysRegisterSettingSet regs_4800 = {
+ { 0x0c, 0x21 },
+ { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0xc1 }, { 0x1d, 0x08 },
+ { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b }, { 0x56, 0x0e },
+ { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x08 }, { 0x71, 0x0a },
+ { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, { 0x7d, 0x90 },
+ { 0x9e, 0xc0 },
+ { 0xaa, 0x07 },
+ };
+
+ GenesysRegisterSettingSet regs_ta_any = {
+ { 0x0c, 0x00 },
+ { 0x16, 0x33 }, { 0x17, 0x4c }, { 0x18, 0x01 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x08 },
+ { 0x52, 0x0e }, { 0x53, 0x11 }, { 0x54, 0x02 }, { 0x55, 0x05 }, { 0x56, 0x08 },
+ { 0x57, 0x0b }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0xc0 },
+ { 0x70, 0x00 }, { 0x71, 0x02 },
+ { 0x74, 0x00 }, { 0x75, 0x1c }, { 0x76, 0x7f },
+ { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff },
+ { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, { 0x7d, 0x90 },
+ { 0x9e, 0x00 },
+ { 0xaa, 0x00 },
+ };
+
CustomSensorSettings custom_settings[] = {
- { { 100, 150, 200, 300, 400, 600 }, 8016, ScanMethod::FLATBED, {
- { 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff },
- { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff },
- { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff },
- { 0x0c, 0x00 },
- { 0x70, 0x00 },
- { 0x71, 0x02 },
- { 0x9e, 0x00 },
- { 0xaa, 0x00 },
- { 0x16, 0x33 },
- { 0x17, 0x0c },
- { 0x18, 0x00 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x08 },
- { 0x52, 0x0b },
- { 0x53, 0x0e },
- { 0x54, 0x11 },
- { 0x55, 0x02 },
- { 0x56, 0x05 },
- { 0x57, 0x08 },
- { 0x58, 0x63 },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
- }
- },
- { { 1200 }, 56064, ScanMethod::FLATBED, {
- { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
- { 0x77, 0x00 }, { 0x78, 0x01 }, { 0x79, 0xff },
- { 0x7a, 0x00 }, { 0x7b, 0x01 }, { 0x7c, 0xff },
- { 0x0c, 0x20 },
- { 0x70, 0x08 },
- { 0x71, 0x0c },
- { 0x9e, 0xc0 },
- { 0xaa, 0x05 },
- { 0x16, 0x3b },
- { 0x17, 0x0c },
- { 0x18, 0x10 },
- { 0x19, 0x2a },
- { 0x1a, 0x38 },
- { 0x1b, 0x10 },
- { 0x1c, 0x00 },
- { 0x1d, 0x08 },
- { 0x52, 0x02 },
- { 0x53, 0x05 },
- { 0x54, 0x08 },
- { 0x55, 0x0b },
- { 0x56, 0x0e },
- { 0x57, 0x11 },
- { 0x58, 0x1b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
- }
- },
- { { 2400 }, 56064, ScanMethod::FLATBED, {
- { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
- { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
- { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 },
- { 0x0c, 0x20 },
- { 0x70, 0x08 },
- { 0x71, 0x0a },
- { 0x9e, 0xc0 },
- { 0xaa, 0x05 },
- { 0x16, 0x3b },
- { 0x17, 0x0c },
- { 0x18, 0x10 },
- { 0x19, 0x2a },
- { 0x1a, 0x38 },
- { 0x1b, 0x10 },
- { 0x1c, 0xc0 },
- { 0x1d, 0x08 },
- { 0x52, 0x02 },
- { 0x53, 0x05 },
- { 0x54, 0x08 },
- { 0x55, 0x0b },
- { 0x56, 0x0e },
- { 0x57, 0x11 },
- { 0x58, 0x1b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
- }
- },
- { { 4800 }, 42752, ScanMethod::FLATBED, {
- { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
- { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
- { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 },
- { 0x0c, 0x21 },
- { 0x70, 0x08 },
- { 0x71, 0x0a },
- { 0x9e, 0xc0 },
- { 0xaa, 0x07 },
- { 0x16, 0x3b },
- { 0x17, 0x0c },
- { 0x18, 0x10 },
- { 0x19, 0x2a },
- { 0x1a, 0x38 },
- { 0x1b, 0x10 },
- { 0x1c, 0xc1 },
- { 0x1d, 0x08 },
- { 0x52, 0x02 },
- { 0x53, 0x05 },
- { 0x54, 0x08 },
- { 0x55, 0x0b },
- { 0x56, 0x0e },
- { 0x57, 0x11 },
- { 0x58, 0x1b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
- }
- },
- { ResolutionFilter::ANY, 15624, ScanMethod::TRANSPARENCY, {
- { 0x74, 0x00 }, { 0x75, 0x1c }, { 0x76, 0x7f },
- { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff },
- { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff },
- { 0x0c, 0x00 },
- { 0x70, 0x00 },
- { 0x71, 0x02 },
- { 0x9e, 0x00 },
- { 0xaa, 0x00 },
- { 0x16, 0x33 },
- { 0x17, 0x4c },
- { 0x18, 0x01 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x08 },
- { 0x52, 0x0e },
- { 0x53, 0x11 },
- { 0x54, 0x02 },
- { 0x55, 0x05 },
- { 0x56, 0x08 },
- { 0x57, 0x0b },
- { 0x58, 0x6b },
- { 0x59, 0x00 },
- { 0x5a, 0xc0 },
- }
- }
+ { { 100 }, 600, 100, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 1,
+ StaggerConfig{}, regs_100_to_600 },
+ { { 150 }, 600, 150, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 1,
+ StaggerConfig{}, regs_100_to_600 },
+ { { 200 }, 600, 200, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 2,
+ StaggerConfig{}, regs_100_to_600 },
+ { { 300 }, 600, 300, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 3,
+ StaggerConfig{}, regs_100_to_600 },
+ { { 400 }, 600, 400, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 4,
+ StaggerConfig{}, regs_100_to_600 },
+ { { 600 }, 600, 600, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 7,
+ StaggerConfig{}, regs_100_to_600 },
+ { { 1200 }, 1200, 1200, 56064, ScanMethod::FLATBED, Ratio{1, 4}, 14,
+ StaggerConfig{}, regs_1200 },
+ { { 2400 }, 2400, 2400, 56064, ScanMethod::FLATBED, Ratio{1, 2}, 29,
+ StaggerConfig{4, 0}, regs_2400 },
+ { { 4800 }, 4800, 4800, 42752, ScanMethod::FLATBED, Ratio{1, 1}, 58,
+ StaggerConfig{8, 0}, regs_4800 },
+ { { 100, 150, 200, 300, 400, 600, 1200 }, 600, 600, 15624, ScanMethod::TRANSPARENCY,
+ Ratio{1, 1}, 58, StaggerConfig{}, regs_ta_any }, // FIXME: may be incorrect
+ { { 2400 }, 600, 600, 15624, ScanMethod::TRANSPARENCY,
+ Ratio{1, 1}, 58, StaggerConfig{4, 0}, regs_ta_any }, // FIXME: may be incorrect
+ { { 4800 }, 600, 600, 15624, ScanMethod::TRANSPARENCY,
+ Ratio{1, 1}, 58, StaggerConfig{8, 0}, regs_ta_any }, // FIXME: may be incorrect
};
auto base_custom_regs = sensor.custom_regs;
for (const CustomSensorSettings& setting : custom_settings)
{
sensor.resolutions = setting.resolutions;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.register_dpihw;
sensor.exposure_lperiod = setting.exposure_lperiod;
sensor.method = setting.method;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.stagger_y = setting.stagger_y;
sensor.custom_regs = base_custom_regs;
sensor.custom_regs.merge(setting.extra_custom_regs);
s_sensors->push_back(sensor);
@@ -2138,110 +1676,136 @@ void genesys_init_sensor_tables()
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_HP_4850C;
- sensor.optical_res = 4800;
+ sensor.sensor_id = SensorId::CCD_HP_4850C; // gl843
+ sensor.full_resolution = 4800;
sensor.black_pixels = 100;
sensor.dummy_pixel = 58;
- sensor.ccd_start_xoffset = 152;
- sensor.sensor_pixels = 5360*8;
sensor.fau_gain_white_ref = 160;
sensor.gain_white_ref = 160;
sensor.exposure = { 0x2c09, 0x22b8, 0x10f0 };
- sensor.stagger_config = StaggerConfig{ 2400, 4 }; // FIXME: may be incorrect
sensor.custom_regs = {};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpihw;
+ unsigned register_dpiset;
int exposure_lperiod;
ScanMethod method;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
+ int shading_pixel_offset;
+ StaggerConfig stagger_y; // FIXME: review, may be incorrect
GenesysRegisterSettingSet extra_custom_regs;
};
+ GenesysRegisterSettingSet regs_100_to_600 = {
+ { 0x0c, 0x00 },
+ { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x08 },
+ { 0x52, 0x0b }, { 0x53, 0x0e }, { 0x54, 0x11 }, { 0x55, 0x02 },
+ { 0x56, 0x05 }, { 0x57, 0x08 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x00 }, { 0x71, 0x02 },
+ { 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff },
+ { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff },
+ { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, { 0x7d, 0x90 },
+ { 0x9e, 0x00 },
+ { 0xaa, 0x00 },
+ };
+ GenesysRegisterSettingSet regs_1200 = {
+ { 0x0c, 0x20 },
+ { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0x00 }, { 0x1d, 0x08 },
+ { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b },
+ { 0x56, 0x0e }, { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x08 }, { 0x71, 0x0c },
+ { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
+ { 0x77, 0x00 }, { 0x78, 0x01 }, { 0x79, 0xff },
+ { 0x7a, 0x00 }, { 0x7b, 0x01 }, { 0x7c, 0xff }, { 0x7d, 0x90 },
+ { 0x9e, 0xc0 },
+ { 0xaa, 0x05 },
+ };
+ GenesysRegisterSettingSet regs_2400 = {
+ { 0x0c, 0x20 },
+ { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0xc0 }, { 0x1d, 0x08 },
+ { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b },
+ { 0x56, 0x0e }, { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x08 }, { 0x71, 0x0a },
+ { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, { 0x7d, 0x90 },
+ { 0x9e, 0xc0 },
+ { 0xaa, 0x05 },
+ };
+ GenesysRegisterSettingSet regs_4800 = {
+ { 0x0c, 0x21 },
+ { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0xc1 }, { 0x1d, 0x08 },
+ { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b },
+ { 0x56, 0x0e }, { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x08 }, { 0x71, 0x0a },
+ { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, { 0x7d, 0x90 },
+ { 0x9e, 0xc0 },
+ { 0xaa, 0x07 },
+ };
+ GenesysRegisterSettingSet regs_ta_any = {
+ { 0x0c, 0x00 },
+ { 0x16, 0x33 }, { 0x17, 0x4c }, { 0x18, 0x01 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x08 },
+ { 0x52, 0x0e }, { 0x53, 0x11 }, { 0x54, 0x02 }, { 0x55, 0x05 },
+ { 0x56, 0x08 }, { 0x57, 0x0b }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0xc0 },
+ { 0x70, 0x00 }, { 0x71, 0x02 },
+ { 0x74, 0x00 }, { 0x75, 0x1c }, { 0x76, 0x7f },
+ { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff },
+ { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, { 0x7d, 0x90 },
+ { 0x9e, 0x00 },
+ { 0xaa, 0x00 },
+ };
+
CustomSensorSettings custom_settings[] = {
- { { 100, 150, 200, 300, 400, 600 }, 8016, ScanMethod::FLATBED, {
- { 0x0c, 0x00 },
- { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0x2a },
- { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x08 },
- { 0x52, 0x0b }, { 0x53, 0x0e }, { 0x54, 0x11 }, { 0x55, 0x02 },
- { 0x56, 0x05 }, { 0x57, 0x08 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0x40 },
- { 0x70, 0x00 }, { 0x71, 0x02 },
- { 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff },
- { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff },
- { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff },
- { 0x9e, 0x00 },
- { 0xaa, 0x00 },
- }
- },
- { { 1200 }, 56064, ScanMethod::FLATBED, {
- { 0x0c, 0x20 },
- { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
- { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0x00 }, { 0x1d, 0x08 },
- { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b },
- { 0x56, 0x0e }, { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
- { 0x70, 0x08 }, { 0x71, 0x0c },
- { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
- { 0x77, 0x00 }, { 0x78, 0x01 }, { 0x79, 0xff },
- { 0x7a, 0x00 }, { 0x7b, 0x01 }, { 0x7c, 0xff },
- { 0x9e, 0xc0 },
- { 0xaa, 0x05 },
- }
- },
- { { 2400 }, 56064, ScanMethod::FLATBED, {
- { 0x0c, 0x20 },
- { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
- { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0xc0 }, { 0x1d, 0x08 },
- { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b },
- { 0x56, 0x0e }, { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
- { 0x70, 0x08 }, { 0x71, 0x0a },
- { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
- { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
- { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 },
- { 0x9e, 0xc0 },
- { 0xaa, 0x05 },
- }
- },
- { { 4800 }, 42752, ScanMethod::FLATBED, {
- { 0x0c, 0x21 },
- { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
- { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0xc1 }, { 0x1d, 0x08 },
- { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b },
- { 0x56, 0x0e }, { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
- { 0x70, 0x08 }, { 0x71, 0x0a },
- { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff },
- { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
- { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 },
- { 0x9e, 0xc0 },
- { 0xaa, 0x07 },
- }
- },
- { ResolutionFilter::ANY, 15624, ScanMethod::TRANSPARENCY, {
- { 0x0c, 0x00 },
- { 0x16, 0x33 }, { 0x17, 0x4c }, { 0x18, 0x01 }, { 0x19, 0x2a },
- { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x08 },
- { 0x52, 0x0e }, { 0x53, 0x11 }, { 0x54, 0x02 }, { 0x55, 0x05 },
- { 0x56, 0x08 }, { 0x57, 0x0b }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0xc0 },
- { 0x70, 0x00 }, { 0x71, 0x02 },
- { 0x74, 0x00 }, { 0x75, 0x1c }, { 0x76, 0x7f },
- { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff },
- { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff },
- { 0x9e, 0x00 },
- { 0xaa, 0x00 },
- }
- }
+ { { 100 }, 600, 100, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 1, 50, StaggerConfig{},
+ regs_100_to_600 },
+ { { 150 }, 600, 150, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 1, 50, StaggerConfig{},
+ regs_100_to_600 },
+ { { 200 }, 600, 200, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 2, 50, StaggerConfig{},
+ regs_100_to_600 },
+ { { 300 }, 600, 300, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 3, 50, StaggerConfig{},
+ regs_100_to_600 },
+ { { 400 }, 600, 400, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 4, 50, StaggerConfig{},
+ regs_100_to_600 },
+ { { 600 }, 600, 600, 8016, ScanMethod::FLATBED, Ratio{1, 8}, 7, 50, StaggerConfig{},
+ regs_100_to_600 },
+ { { 1200 }, 1200, 1200, 56064, ScanMethod::FLATBED, Ratio{1, 4}, 14, 0,
+ StaggerConfig{}, regs_1200 },
+ { { 2400 }, 2400, 2400, 56064, ScanMethod::FLATBED, Ratio{1, 2}, 29, 0,
+ StaggerConfig{0, 4}, regs_2400 },
+ { { 4800 }, 4800, 4800, 42752, ScanMethod::FLATBED, Ratio{1, 1}, 58, 0,
+ StaggerConfig{0, 8}, regs_4800 },
+ { { 100, 150, 200, 300, 400, 600, 1200}, 600, 600, 15624, ScanMethod::TRANSPARENCY,
+ Ratio{1, 1}, 58, 0, StaggerConfig{}, regs_ta_any }, // FIXME: review
+ { { 2400 }, 600, 600, 15624, ScanMethod::TRANSPARENCY,
+ Ratio{1, 1}, 58, 0, StaggerConfig{0, 4}, regs_ta_any }, // FIXME: review
+ { { 4800 }, 600, 600, 15624, ScanMethod::TRANSPARENCY,
+ Ratio{1, 1}, 58, 0, StaggerConfig{0, 8}, regs_ta_any }, // FIXME: review
};
auto base_custom_regs = sensor.custom_regs;
for (const CustomSensorSettings& setting : custom_settings)
{
sensor.resolutions = setting.resolutions;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.register_dpihw;
sensor.exposure_lperiod = setting.exposure_lperiod;
sensor.method = setting.method;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.shading_pixel_offset = setting.shading_pixel_offset;
+ sensor.stagger_y = setting.stagger_y;
sensor.custom_regs = base_custom_regs;
sensor.custom_regs.merge(setting.extra_custom_regs);
s_sensors->push_back(sensor);
@@ -2249,142 +1813,250 @@ void genesys_init_sensor_tables()
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_CANON_4400F;
- sensor.optical_res = 4800;
- sensor.ccd_size_divisor = 4;
+ sensor.sensor_id = SensorId::CCD_CANON_4400F; // gl843
+ sensor.full_resolution = 4800;
+ sensor.register_dpihw = 4800;
sensor.black_pixels = 50*8;
// 31 at 600 dpi, 58 at 1200 dpi
sensor.dummy_pixel = 20;
- sensor.ccd_start_xoffset = 152;
- // 5360 max at 600 dpi
- sensor.sensor_pixels = 5700 * 8;
sensor.fau_gain_white_ref = 160;
sensor.gain_white_ref = 160;
sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 };
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = get_sensor_optical_with_ccd_divisor;
- sensor.get_register_hwdpi_fun = [](const Genesys_Sensor&, unsigned) { return 4800; };
- sensor.get_hwdpi_divisor_fun = [](const Genesys_Sensor&, unsigned) { return 1; };
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpiset;
int exposure_lperiod;
+ bool use_host_side_calib;
+ int output_pixel_offset;
std::vector<ScanMethod> methods;
+ StaggerConfig stagger_y;
GenesysRegisterSettingSet extra_custom_regs;
+ GenesysRegisterSettingSet extra_custom_fe_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 300, 600, 1200 }, 11640, { ScanMethod::FLATBED }, {
- { 0x16, 0x13 },
- { 0x17, 0x0a },
- { 0x18, 0x10 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x6b },
- { 0x52, 0x0a },
- { 0x53, 0x0d },
- { 0x54, 0x00 },
- { 0x55, 0x03 },
- { 0x56, 0x06 },
- { 0x57, 0x08 },
- { 0x58, 0x5b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
+ { { 300 }, 1200, 1200, 11640, false, 197, { ScanMethod::FLATBED }, StaggerConfig{}, {
+ { 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b },
+ { 0x52, 0x0a }, { 0x53, 0x0d }, { 0x54, 0x00 }, { 0x55, 0x03 },
+ { 0x56, 0x06 }, { 0x57, 0x08 }, { 0x58, 0x5b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
{ 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x01 }, { 0x73, 0x03 },
{ 0x74, 0x00 }, { 0x75, 0xf8 }, { 0x76, 0x38 },
{ 0x77, 0x00 }, { 0x78, 0xfc }, { 0x79, 0x00 },
{ 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0xa4 },
{ 0x9e, 0x2d },
- }
+ }, {}
+ },
+ { { 600 }, 1200, 2400, 11640, false, 392, { ScanMethod::FLATBED }, StaggerConfig{}, {
+ { 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b },
+ { 0x52, 0x0a }, { 0x53, 0x0d }, { 0x54, 0x00 }, { 0x55, 0x03 },
+ { 0x56, 0x06 }, { 0x57, 0x08 }, { 0x58, 0x5b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x01 }, { 0x73, 0x03 },
+ { 0x74, 0x00 }, { 0x75, 0xf8 }, { 0x76, 0x38 },
+ { 0x77, 0x00 }, { 0x78, 0xfc }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0xa4 },
+ { 0x9e, 0x2d },
+ }, {}
+ },
+ { { 1200 }, 1200, 4800, 11640, false, 794, { ScanMethod::FLATBED }, StaggerConfig{}, {
+ { 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b },
+ { 0x52, 0x0a }, { 0x53, 0x0d }, { 0x54, 0x00 }, { 0x55, 0x03 },
+ { 0x56, 0x06 }, { 0x57, 0x08 }, { 0x58, 0x5b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x01 }, { 0x73, 0x03 },
+ { 0x74, 0x00 }, { 0x75, 0xf8 }, { 0x76, 0x38 },
+ { 0x77, 0x00 }, { 0x78, 0xfc }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0xa4 },
+ { 0x9e, 0x2d },
+ }, {}
},
- { { 300, 600, 1200 }, 33300, { ScanMethod::TRANSPARENCY }, {
- { 0x16, 0x13 },
- { 0x17, 0x0a },
- { 0x18, 0x10 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x6b },
- { 0x52, 0x0a },
- { 0x53, 0x0d },
- { 0x54, 0x00 },
- { 0x55, 0x03 },
- { 0x56, 0x06 },
- { 0x57, 0x08 },
- { 0x58, 0x5b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
+ { { 1200 }, 1200, 4800, 33300, true, 5, { ScanMethod::TRANSPARENCY },
+ StaggerConfig{}, {
+ { 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b },
+ { 0x52, 0x0a }, { 0x53, 0x0d }, { 0x54, 0x00 }, { 0x55, 0x03 },
+ { 0x56, 0x06 }, { 0x57, 0x08 }, { 0x58, 0x5b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
{ 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x00 }, { 0x73, 0x02 },
{ 0x74, 0x00 }, { 0x75, 0xf8 }, { 0x76, 0x38 },
{ 0x77, 0x00 }, { 0x78, 0xfc }, { 0x79, 0x00 },
{ 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0xa4 },
{ 0x9e, 0x2d },
- }
+ }, {}
},
- { { 2400 }, 33300, { ScanMethod::TRANSPARENCY }, {
- { 0x16, 0x13 },
- { 0x17, 0x0a },
- { 0x18, 0x10 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x01 },
- { 0x1d, 0x75 },
- { 0x52, 0x0b },
- { 0x53, 0x0d },
- { 0x54, 0x00 },
- { 0x55, 0x03 },
- { 0x56, 0x06 },
- { 0x57, 0x09 },
- { 0x58, 0x53 },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
+ { { 2400 }, 2400, 4800, 33300, true, 10, { ScanMethod::TRANSPARENCY },
+ StaggerConfig{}, {
+ { 0x16, 0x13 }, { 0x17, 0x15 }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x01 }, { 0x1d, 0x75 },
+ { 0x52, 0x0b }, { 0x53, 0x0d }, { 0x54, 0x00 }, { 0x55, 0x03 },
+ { 0x56, 0x06 }, { 0x57, 0x09 }, { 0x58, 0x53 }, { 0x59, 0x00 }, { 0x5a, 0x40 },
{ 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x02 }, { 0x73, 0x04 },
{ 0x74, 0x00 }, { 0x75, 0xff }, { 0x76, 0x00 },
{ 0x77, 0x00 }, { 0x78, 0xff }, { 0x79, 0x00 },
{ 0x7a, 0x00 }, { 0x7b, 0x54 }, { 0x7c, 0x92 },
{ 0x9e, 0x2d },
+ }, {
+ { 0x03, 0x1f },
}
},
- { { 4800 }, 33300, { ScanMethod::TRANSPARENCY }, {
- { 0x16, 0x13 },
- { 0x17, 0x0a },
- { 0x18, 0x10 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x61 },
- { 0x1d, 0x75 },
- { 0x52, 0x02 },
- { 0x53, 0x05 },
- { 0x54, 0x08 },
- { 0x55, 0x0b },
- { 0x56, 0x0d },
- { 0x57, 0x0f },
- { 0x58, 0x1b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
+ { { 4800 }, 4800, 4800, 33300, true, -2063, { ScanMethod::TRANSPARENCY },
+ StaggerConfig{0, 8}, {
+ { 0x16, 0x13 }, { 0x17, 0x15 }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x61 }, { 0x1d, 0x75 },
+ { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b },
+ { 0x56, 0x0d }, { 0x57, 0x0f }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
{ 0x70, 0x08 }, { 0x71, 0x0a }, { 0x72, 0x0a }, { 0x73, 0x0c },
{ 0x74, 0x00 }, { 0x75, 0xff }, { 0x76, 0xff },
{ 0x77, 0x00 }, { 0x78, 0xff }, { 0x79, 0xff },
{ 0x7a, 0x00 }, { 0x7b, 0x54 }, { 0x7c, 0x92 },
{ 0x9e, 0x2d },
- }
+ }, {}
}
};
for (const CustomSensorSettings& setting : custom_settings)
{
for (auto method : setting.methods) {
+ for (auto resolution : setting.resolutions.values()) {
+ sensor.resolutions = { resolution };
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = resolution;
+ sensor.exposure_lperiod = setting.exposure_lperiod;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.use_host_side_calib = setting.use_host_side_calib;
+ sensor.method = method;
+ sensor.stagger_y = setting.stagger_y;
+ sensor.custom_regs = setting.extra_custom_regs;
+ sensor.custom_fe_regs = setting.extra_custom_fe_regs;
+ s_sensors->push_back(sensor);
+ }
+ }
+ }
+ }
+
+
+ sensor = Genesys_Sensor();
+ sensor.sensor_id = SensorId::CCD_CANON_5600F; // gl847
+ sensor.full_resolution = 4800;
+ sensor.register_dpihw = 4800;
+ sensor.black_pixels = 50*8;
+ sensor.dummy_pixel = 10;
+ sensor.fau_gain_white_ref = 160;
+ sensor.gain_white_ref = 160;
+ sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 };
+ sensor.gamma = { 1.0f, 1.0f, 1.0f };
+ sensor.use_host_side_calib = true;
+ {
+ struct CustomSensorSettings {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpihw;
+ unsigned register_dpiset;
+ int exposure_lperiod;
+ SensorExposure exposure;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
+ unsigned segment_size;
+ std::vector<unsigned> segment_order;
+ StaggerConfig stagger_x;
+ StaggerConfig stagger_y;
+ GenesysRegisterSettingSet custom_regs;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 150 }, 2400, 600, 300, 4288, { 3983/2, 3983/2, 3983/2 }, Ratio{1, 8}, 10,
+ 5418, std::vector<unsigned>{}, StaggerConfig{}, StaggerConfig{}, {
+ { 0x16, 0x00 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x10 }, { 0x1c, 0x08 }, { 0x1d, 0x02 },
+ { 0x52, 0x0e }, { 0x53, 0x00 }, { 0x54, 0x02 }, { 0x55, 0x04 },
+ { 0x56, 0x06 }, { 0x57, 0x08 }, { 0x58, 0x52 }, { 0x59, 0x3a }, { 0x5a, 0x40 },
+ { 0x74, 0x00 }, { 0x75, 0x33 }, { 0x76, 0x33 },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, { 0x87, 0x00 },
+ }
+ },
+ { { 300 }, 2400, 600, 600, 5472, { 4558/2, 4558/2, 4558/2 }, Ratio{1, 8}, 110,
+ 5418, std::vector<unsigned>{}, StaggerConfig{}, StaggerConfig{}, {
+ { 0x16, 0x00 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x10 }, { 0x1c, 0x08 }, { 0x1d, 0x02 },
+ { 0x52, 0x0e }, { 0x53, 0x00 }, { 0x54, 0x02 }, { 0x55, 0x04 },
+ { 0x56, 0x06 }, { 0x57, 0x08 }, { 0x58, 0x52 }, { 0x59, 0x3a }, { 0x5a, 0x40 },
+ { 0x74, 0x00 }, { 0x75, 0x33 }, { 0x76, 0x33 },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, { 0x87, 0x00 },
+ }
+ },
+ { { 600 }, 2400, 600, 600, 10944, { 8701/2, 8701/2, 8701/2 }, Ratio{1, 4}, 155,
+ 5418, std::vector<unsigned>{}, StaggerConfig{}, StaggerConfig{}, {
+ { 0x16, 0x00 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x10 }, { 0x1c, 0x08 }, { 0x1d, 0x02 },
+ { 0x52, 0x02 }, { 0x53, 0x04 }, { 0x54, 0x06 }, { 0x55, 0x08 },
+ { 0x56, 0x0a }, { 0x57, 0x0c }, { 0x58, 0x72 }, { 0x59, 0x5a }, { 0x5a, 0x40 },
+ { 0x74, 0x00 }, { 0x75, 0x33 }, { 0x76, 0x33 },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, { 0x87, 0x00 },
+ }
+ },
+ { { 1200 }, 2400, 1200, 1200, 29120, { 17120/2, 17120/2, 17120/2 }, Ratio{1, 2}, 295,
+ 5418, { 1, 0 }, StaggerConfig{}, StaggerConfig{}, {
+ { 0x16, 0x00 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x10 }, { 0x1c, 0x08 }, { 0x1d, 0x02 },
+ { 0x52, 0x02 }, { 0x53, 0x04 }, { 0x54, 0x06 }, { 0x55, 0x08 },
+ { 0x56, 0x0a }, { 0x57, 0x0c }, { 0x58, 0x72 }, { 0x59, 0x5a }, { 0x5a, 0x40 },
+ { 0x74, 0x00 }, { 0x75, 0x33 }, { 0x76, 0x33 },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, { 0x87, 0x00 },
+ }
+ },
+ { { 2400 }, 2400, 2400, 2400, 43776, { 36725/2, 36725/2, 36725/2 }, Ratio{1, 1}, 600,
+ 5418, { 0, 1, 2, 3 },
+ StaggerConfig{10, 15, 4, 9, 14, 19, 8, 13}, StaggerConfig{}, {
+ { 0x16, 0x00 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x10 }, { 0x1c, 0x08 }, { 0x1d, 0x02 },
+ { 0x52, 0x02 }, { 0x53, 0x04 }, { 0x54, 0x06 }, { 0x55, 0x08 },
+ { 0x56, 0x0a }, { 0x57, 0x0c }, { 0x58, 0x72 }, { 0x59, 0x5a }, { 0x5a, 0x40 },
+ { 0x74, 0x00 }, { 0x75, 0x33 }, { 0x76, 0x33 },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, { 0x87, 0x00 },
+ }
+ },
+ { { 4800 }, 4800, 4800, 4800, 43776, { 36725/2, 36725/2, 36725/2 }, Ratio{1, 1}, 1000,
+ 10784, { 0, 1, 2, 3 },
+ StaggerConfig{5, 9, 6, 10, 3, 7, 16, 20, 13, 17, 14, 18, 11, 15, 24, 28},
+ StaggerConfig{6, 0}, {
+ { 0x16, 0x00 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x10 }, { 0x1c, 0x08 }, { 0x1d, 0x02 },
+ { 0x52, 0x0a }, { 0x53, 0x0c }, { 0x54, 0x0e }, { 0x55, 0x00 },
+ { 0x56, 0x02 }, { 0x57, 0x04 }, { 0x58, 0x32 }, { 0x59, 0x1a }, { 0x5a, 0x40 },
+ { 0x74, 0x00 }, { 0x75, 0x33 }, { 0x76, 0x33 },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, { 0x87, 0x00 },
+ }
+ }
+ };
+
+ for (const auto& setting : custom_settings) {
+ for (auto method : { ScanMethod::FLATBED, ScanMethod::TRANSPARENCY }) {
+ sensor.method = method;
sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.resolutions.values().front();
sensor.exposure_lperiod = setting.exposure_lperiod;
- sensor.method = method;
- sensor.custom_regs = setting.extra_custom_regs;
+ sensor.exposure = setting.exposure;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.segment_size = setting.segment_size;
+ sensor.segment_order = setting.segment_order;
+ sensor.stagger_x = setting.stagger_x;
+ sensor.stagger_y = setting.stagger_y;
+ sensor.custom_regs = setting.custom_regs;
s_sensors->push_back(sensor);
}
}
@@ -2392,57 +2064,39 @@ void genesys_init_sensor_tables()
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_CANON_8400F;
- sensor.optical_res = 3200;
- sensor.register_dpihw_override = 4800;
- sensor.ccd_size_divisor = 1;
+ sensor.sensor_id = SensorId::CCD_CANON_8400F; // gl843
+ sensor.full_resolution = 3200;
+ sensor.register_dpihw = 4800;
sensor.black_pixels = 50*8;
// 31 at 600 dpi, 58 at 1200 dpi
sensor.dummy_pixel = 20;
- sensor.ccd_start_xoffset = 152;
- sensor.sensor_pixels = 27200;
sensor.fau_gain_white_ref = 160;
sensor.gain_white_ref = 160;
sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 };
- sensor.stagger_config = StaggerConfig{ 3200, 6 };
sensor.custom_regs = {};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = get_sensor_optical_with_ccd_divisor;
- sensor.get_register_hwdpi_fun = [](const Genesys_Sensor&, unsigned) { return 4800; };
- sensor.get_hwdpi_divisor_fun = [](const Genesys_Sensor&, unsigned) { return 1; };
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
- unsigned dpiset_override;
- unsigned pixel_count_multiplier;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
+ Ratio pixel_count_ratio;
int exposure_lperiod;
+ int output_pixel_offset;
+ int shading_pixel_offset;
std::vector<ScanMethod> methods;
+ StaggerConfig stagger_y;
GenesysRegisterSettingSet extra_custom_regs;
GenesysRegisterSettingSet custom_fe_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 400 }, 2400, 1, 7200, { ScanMethod::FLATBED }, {
- { 0x16, 0x33 },
- { 0x17, 0x0c },
- { 0x18, 0x13 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x84 },
- { 0x1e, 0xa0 },
- { 0x52, 0x0d },
- { 0x53, 0x10 },
- { 0x54, 0x01 },
- { 0x55, 0x04 },
- { 0x56, 0x07 },
- { 0x57, 0x0a },
- { 0x58, 0x6b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
+ { { 400 }, 2400, Ratio{1, 4}, 7200, 2, 0, { ScanMethod::FLATBED },
+ StaggerConfig{}, {
+ { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x13 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x84 }, { 0x1e, 0xa0 },
+ { 0x52, 0x0d }, { 0x53, 0x10 }, { 0x54, 0x01 }, { 0x55, 0x04 },
+ { 0x56, 0x07 }, { 0x57, 0x0a }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
{ 0x70, 0x01 }, { 0x71, 0x02 }, { 0x72, 0x03 }, { 0x73, 0x04 },
{ 0x74, 0x00 }, { 0x75, 0x0e }, { 0x76, 0x3f },
{ 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
@@ -2450,25 +2104,12 @@ void genesys_init_sensor_tables()
{ 0x80, 0x2a },
}, {}
},
- { { 800 }, 4800, 1, 7200, { ScanMethod::FLATBED }, {
- { 0x16, 0x33 },
- { 0x17, 0x0c },
- { 0x18, 0x13 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x84 },
- { 0x1e, 0xa0 },
- { 0x52, 0x0d },
- { 0x53, 0x10 },
- { 0x54, 0x01 },
- { 0x55, 0x04 },
- { 0x56, 0x07 },
- { 0x57, 0x0a },
- { 0x58, 0x6b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
+ { { 800 }, 4800, Ratio{1, 4}, 7200, 5, 13, { ScanMethod::FLATBED },
+ StaggerConfig{}, {
+ { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x13 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x84 }, { 0x1e, 0xa0 },
+ { 0x52, 0x0d }, { 0x53, 0x10 }, { 0x54, 0x01 }, { 0x55, 0x04 },
+ { 0x56, 0x07 }, { 0x57, 0x0a }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
{ 0x70, 0x01 }, { 0x71, 0x02 }, { 0x72, 0x03 }, { 0x73, 0x04 },
{ 0x74, 0x00 }, { 0x75, 0x0e }, { 0x76, 0x3f },
{ 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
@@ -2476,26 +2117,13 @@ void genesys_init_sensor_tables()
{ 0x80, 0x20 },
}, {}
},
- { { 1600 }, 4800, 1, 14400, { ScanMethod::FLATBED }, {
- { 0x16, 0x33 },
- { 0x17, 0x0c },
- { 0x18, 0x11 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x84 },
- { 0x1e, 0xa1 },
- { 0x52, 0x0b },
- { 0x53, 0x0e },
- { 0x54, 0x11 },
- { 0x55, 0x02 },
- { 0x56, 0x05 },
- { 0x57, 0x08 },
- { 0x58, 0x63 },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
- { 0x70, 0x01 }, { 0x71, 0x02 }, { 0x72, 0x02 }, { 0x73, 0x03 },
+ { { 1600 }, 4800, Ratio{1, 2}, 14400, 10, 8, { ScanMethod::FLATBED },
+ StaggerConfig{}, {
+ { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x11 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x84 }, { 0x1e, 0xa1 },
+ { 0x52, 0x0b }, { 0x53, 0x0e }, { 0x54, 0x11 }, { 0x55, 0x02 },
+ { 0x56, 0x05 }, { 0x57, 0x08 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x00 }, { 0x71, 0x01 }, { 0x72, 0x02 }, { 0x73, 0x03 },
{ 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff },
{ 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
{ 0x7a, 0x02 }, { 0x7b, 0x49 }, { 0x7c, 0x24 },
@@ -2504,25 +2132,12 @@ void genesys_init_sensor_tables()
{ 0x03, 0x1f },
}
},
- { { 3200 }, 4800, 1, 28800, { ScanMethod::FLATBED }, {
- { 0x16, 0x33 },
- { 0x17, 0x0c },
- { 0x18, 0x10 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x20 },
- { 0x1d, 0x84 },
- { 0x1e, 0xa1 },
- { 0x52, 0x02 },
- { 0x53, 0x05 },
- { 0x54, 0x08 },
- { 0x55, 0x0b },
- { 0x56, 0x0e },
- { 0x57, 0x11 },
- { 0x58, 0x1b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
+ { { 3200 }, 4800, Ratio{1, 1}, 28800, 20, -2, { ScanMethod::FLATBED },
+ StaggerConfig{0, 6}, {
+ { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x84 }, { 0x1e, 0xa1 },
+ { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b },
+ { 0x56, 0x0e }, { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
{ 0x70, 0x09 }, { 0x71, 0x0a }, { 0x72, 0x0b }, { 0x73, 0x0c },
{ 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 },
{ 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
@@ -2532,26 +2147,13 @@ void genesys_init_sensor_tables()
{ 0x03, 0x1f },
},
},
- { { 400 }, 2400, 1, 14400, { ScanMethod::TRANSPARENCY,
- ScanMethod::TRANSPARENCY_INFRARED }, {
- { 0x16, 0x33 },
- { 0x17, 0x0c },
- { 0x18, 0x13 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x84 },
- { 0x1e, 0xa0 },
- { 0x52, 0x0d },
- { 0x53, 0x10 },
- { 0x54, 0x01 },
- { 0x55, 0x04 },
- { 0x56, 0x07 },
- { 0x57, 0x0a },
- { 0x58, 0x6b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
+ { { 400 }, 2400, Ratio{1, 4}, 14400, 2, 0, { ScanMethod::TRANSPARENCY,
+ ScanMethod::TRANSPARENCY_INFRARED },
+ StaggerConfig{}, {
+ { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x13 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x84 }, { 0x1e, 0xa0 },
+ { 0x52, 0x0d }, { 0x53, 0x10 }, { 0x54, 0x01 }, { 0x55, 0x04 },
+ { 0x56, 0x07 }, { 0x57, 0x0a }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
{ 0x70, 0x01 }, { 0x71, 0x02 }, { 0x72, 0x03 }, { 0x73, 0x04 },
{ 0x74, 0x00 }, { 0x75, 0x0e }, { 0x76, 0x3f },
{ 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
@@ -2559,53 +2161,27 @@ void genesys_init_sensor_tables()
{ 0x80, 0x20 },
}, {}
},
- { { 800 }, 4800, 1, 14400, { ScanMethod::TRANSPARENCY,
- ScanMethod::TRANSPARENCY_INFRARED }, {
- { 0x16, 0x33 },
- { 0x17, 0x0c },
- { 0x18, 0x13 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x84 },
- { 0x1e, 0xa0 },
- { 0x52, 0x0d },
- { 0x53, 0x10 },
- { 0x54, 0x01 },
- { 0x55, 0x04 },
- { 0x56, 0x07 },
- { 0x57, 0x0a },
- { 0x58, 0x6b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
- { 0x70, 0x01 }, { 0x71, 0x02 }, { 0x72, 0x03 }, { 0x73, 0x04 },
+ { { 800 }, 4800, Ratio{1, 4}, 14400, 5, 13, { ScanMethod::TRANSPARENCY,
+ ScanMethod::TRANSPARENCY_INFRARED },
+ StaggerConfig{}, {
+ { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x13 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x84 }, { 0x1e, 0xa0 },
+ { 0x52, 0x0d }, { 0x53, 0x10 }, { 0x54, 0x01 }, { 0x55, 0x04 },
+ { 0x56, 0x07 }, { 0x57, 0x0a }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x00 }, { 0x71, 0x01 }, { 0x72, 0x02 }, { 0x73, 0x03 },
{ 0x74, 0x00 }, { 0x75, 0x0e }, { 0x76, 0x3f },
{ 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
{ 0x7a, 0x01 }, { 0x7b, 0xb6 }, { 0x7c, 0xdb },
{ 0x80, 0x20 },
}, {}
},
- { { 1600 }, 4800, 1, 28800, { ScanMethod::TRANSPARENCY,
- ScanMethod::TRANSPARENCY_INFRARED }, {
- { 0x16, 0x33 },
- { 0x17, 0x0c },
- { 0x18, 0x11 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x84 },
- { 0x1e, 0xa0 },
- { 0x52, 0x0b },
- { 0x53, 0x0e },
- { 0x54, 0x11 },
- { 0x55, 0x02 },
- { 0x56, 0x05 },
- { 0x57, 0x08 },
- { 0x58, 0x63 },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
+ { { 1600 }, 4800, Ratio{1, 2}, 28800, 10, 8, { ScanMethod::TRANSPARENCY,
+ ScanMethod::TRANSPARENCY_INFRARED },
+ StaggerConfig{}, {
+ { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x11 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x84 }, { 0x1e, 0xa0 },
+ { 0x52, 0x0b }, { 0x53, 0x0e }, { 0x54, 0x11 }, { 0x55, 0x02 },
+ { 0x56, 0x05 }, { 0x57, 0x08 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0x40 },
{ 0x70, 0x00 }, { 0x71, 0x01 }, { 0x72, 0x02 }, { 0x73, 0x03 },
{ 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff },
{ 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
@@ -2615,26 +2191,13 @@ void genesys_init_sensor_tables()
{ 0x03, 0x1f },
},
},
- { { 3200 }, 4800, 1, 28800, { ScanMethod::TRANSPARENCY,
- ScanMethod::TRANSPARENCY_INFRARED }, {
- { 0x16, 0x33 },
- { 0x17, 0x0c },
- { 0x18, 0x10 },
- { 0x19, 0x2a },
- { 0x1a, 0x30 },
- { 0x1b, 0x00 },
- { 0x1c, 0x20 },
- { 0x1d, 0x84 },
- { 0x1e, 0xa0 },
- { 0x52, 0x02 },
- { 0x53, 0x05 },
- { 0x54, 0x08 },
- { 0x55, 0x0b },
- { 0x56, 0x0e },
- { 0x57, 0x11 },
- { 0x58, 0x1b },
- { 0x59, 0x00 },
- { 0x5a, 0x40 },
+ { { 3200 }, 4800, Ratio{1, 1}, 28800, 20, 10, { ScanMethod::TRANSPARENCY,
+ ScanMethod::TRANSPARENCY_INFRARED },
+ StaggerConfig{0, 6}, {
+ { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x84 }, { 0x1e, 0xa0 },
+ { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b },
+ { 0x56, 0x0e }, { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
{ 0x70, 0x09 }, { 0x71, 0x0a }, { 0x72, 0x0b }, { 0x73, 0x0c },
{ 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 },
{ 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
@@ -2648,51 +2211,68 @@ void genesys_init_sensor_tables()
for (const CustomSensorSettings& setting : custom_settings)
{
- for (auto method : setting.methods) {
- sensor.resolutions = setting.resolutions;
- sensor.dpiset_override = setting.dpiset_override;
- sensor.pixel_count_multiplier = setting.pixel_count_multiplier;
- sensor.exposure_lperiod = setting.exposure_lperiod;
- sensor.method = method;
- sensor.custom_regs = setting.extra_custom_regs;
- sensor.custom_fe_regs = setting.custom_fe_regs;
- s_sensors->push_back(sensor);
+ for (auto method : setting.methods)
+ {for (auto resolution : setting.resolutions.values()) {
+ sensor.resolutions = { resolution };
+ sensor.shading_resolution = resolution;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.exposure_lperiod = setting.exposure_lperiod;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.shading_pixel_offset = setting.shading_pixel_offset;
+ sensor.method = method;
+ sensor.stagger_y = setting.stagger_y;
+ sensor.custom_regs = setting.extra_custom_regs;
+ sensor.custom_fe_regs = setting.custom_fe_regs;
+ s_sensors->push_back(sensor);
+ }
}
}
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_CANON_8600F;
- sensor.optical_res = 4800;
- sensor.ccd_size_divisor = 4;
+ sensor.sensor_id = SensorId::CCD_CANON_8600F; // gl843
+ sensor.full_resolution = 4800;
+ sensor.register_dpihw = 4800;
sensor.black_pixels = 31;
sensor.dummy_pixel = 20;
- sensor.ccd_start_xoffset = 0; // not used at the moment
- // 11372 pixels at 1200 dpi
- sensor.sensor_pixels = 11372*4;
sensor.fau_gain_white_ref = 160;
sensor.gain_white_ref = 160;
sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 };
- sensor.stagger_config = StaggerConfig{4800, 8};
sensor.custom_regs = {};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = get_sensor_optical_with_ccd_divisor;
- sensor.get_register_hwdpi_fun = [](const Genesys_Sensor&, unsigned) { return 4800; };
- sensor.get_hwdpi_divisor_fun = [](const Genesys_Sensor&, unsigned) { return 1; };
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpiset;
int exposure_lperiod;
+ int output_pixel_offset;
std::vector<ScanMethod> methods;
+ StaggerConfig stagger_y;
GenesysRegisterSettingSet extra_custom_regs;
GenesysRegisterSettingSet custom_fe_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 300, 600, 1200 }, 24000, { ScanMethod::FLATBED }, {
+ { { 300 }, 1200, 1200, 24000, 1, { ScanMethod::FLATBED }, StaggerConfig{}, {
+ { 0x0c, 0x00 },
+ { 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b },
+ { 0x52, 0x0c }, { 0x53, 0x0f }, { 0x54, 0x00 }, { 0x55, 0x03 },
+ { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x02 }, { 0x73, 0x04 },
+ { 0x56, 0x06 }, { 0x57, 0x09 }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x74, 0x03 }, { 0x75, 0xf0 }, { 0x76, 0xf0 },
+ { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 },
+ { 0x9e, 0x2d },
+ { 0xaa, 0x00 },
+ },
+ {},
+ },
+ { { 600 }, 1200, 2400, 24000, 2, { ScanMethod::FLATBED }, StaggerConfig{}, {
{ 0x0c, 0x00 },
{ 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b },
@@ -2707,8 +2287,24 @@ void genesys_init_sensor_tables()
},
{},
},
- { { 300, 600, 1200 }, 45000, { ScanMethod::TRANSPARENCY,
- ScanMethod::TRANSPARENCY_INFRARED }, {
+ { { 1200 }, 1200, 4800, 24000, 5, { ScanMethod::FLATBED }, StaggerConfig{}, {
+ { 0x0c, 0x00 },
+ { 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b },
+ { 0x52, 0x0c }, { 0x53, 0x0f }, { 0x54, 0x00 }, { 0x55, 0x03 },
+ { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x02 }, { 0x73, 0x04 },
+ { 0x56, 0x06 }, { 0x57, 0x09 }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x74, 0x03 }, { 0x75, 0xf0 }, { 0x76, 0xf0 },
+ { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 },
+ { 0x9e, 0x2d },
+ { 0xaa, 0x00 },
+ },
+ {},
+ },
+ { { 300 }, 1200, 1200, 45000, 6, { ScanMethod::TRANSPARENCY,
+ ScanMethod::TRANSPARENCY_INFRARED },
+ StaggerConfig{}, {
{ 0x0c, 0x00 },
{ 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b },
@@ -2723,8 +2319,43 @@ void genesys_init_sensor_tables()
},
{},
},
- { { 2400 }, 45000, { ScanMethod::TRANSPARENCY,
- ScanMethod::TRANSPARENCY_INFRARED }, {
+ { { 600 }, 1200, 2400, 45000, 11, { ScanMethod::TRANSPARENCY,
+ ScanMethod::TRANSPARENCY_INFRARED },
+ StaggerConfig{}, {
+ { 0x0c, 0x00 },
+ { 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b },
+ { 0x52, 0x0c }, { 0x53, 0x0f }, { 0x54, 0x00 }, { 0x55, 0x03 },
+ { 0x56, 0x06 }, { 0x57, 0x09 }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x02 }, { 0x73, 0x04 },
+ { 0x74, 0x03 }, { 0x75, 0xf0 }, { 0x76, 0xf0 },
+ { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 },
+ { 0x9e, 0x2d },
+ { 0xaa, 0x00 },
+ },
+ {},
+ },
+ { { 1200 }, 1200, 4800, 45000, 23, { ScanMethod::TRANSPARENCY,
+ ScanMethod::TRANSPARENCY_INFRARED },
+ StaggerConfig{}, {
+ { 0x0c, 0x00 },
+ { 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b },
+ { 0x52, 0x0c }, { 0x53, 0x0f }, { 0x54, 0x00 }, { 0x55, 0x03 },
+ { 0x56, 0x06 }, { 0x57, 0x09 }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0x40 },
+ { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x02 }, { 0x73, 0x04 },
+ { 0x74, 0x03 }, { 0x75, 0xf0 }, { 0x76, 0xf0 },
+ { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 },
+ { 0x9e, 0x2d },
+ { 0xaa, 0x00 },
+ },
+ {},
+ },
+ { { 2400 }, 2400, 4800, 45000, 10, { ScanMethod::TRANSPARENCY,
+ ScanMethod::TRANSPARENCY_INFRARED },
+ StaggerConfig{}, {
{ 0x0c, 0x00 },
{ 0x16, 0x13 }, { 0x17, 0x15 }, { 0x18, 0x10 }, { 0x19, 0x2a },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x01 }, { 0x1d, 0x75 },
@@ -2739,8 +2370,9 @@ void genesys_init_sensor_tables()
},
{},
},
- { { 4800 }, 45000, { ScanMethod::TRANSPARENCY,
- ScanMethod::TRANSPARENCY_INFRARED }, {
+ { { 4800 }, 4800, 4800, 45000, -1982, { ScanMethod::TRANSPARENCY,
+ ScanMethod::TRANSPARENCY_INFRARED },
+ StaggerConfig{8, 0}, {
{ 0x0c, 0x00 },
{ 0x16, 0x13 }, { 0x17, 0x15 }, { 0x18, 0x10 }, { 0x19, 0x2a },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x61 }, { 0x1d, 0x75 },
@@ -2760,25 +2392,30 @@ void genesys_init_sensor_tables()
for (const CustomSensorSettings& setting : custom_settings) {
for (auto method : setting.methods) {
- sensor.resolutions = setting.resolutions;
- sensor.method = method;
- sensor.exposure_lperiod = setting.exposure_lperiod;
- sensor.custom_regs = setting.extra_custom_regs;
- sensor.custom_fe_regs = setting.custom_fe_regs;
- s_sensors->push_back(sensor);
+ for (auto resolution : setting.resolutions.values()) {
+ sensor.resolutions = { resolution };
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = resolution;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.method = method;
+ sensor.exposure_lperiod = setting.exposure_lperiod;
+ sensor.stagger_y = setting.stagger_y;
+ sensor.custom_regs = setting.extra_custom_regs;
+ sensor.custom_fe_regs = setting.custom_fe_regs;
+ s_sensors->push_back(sensor);
+ }
}
}
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_HP_N6310;
- sensor.optical_res = 2400;
- // sensor.ccd_size_divisor = 2; Possibly half CCD, needs checking
+ sensor.sensor_id = SensorId::CCD_HP_N6310; // gl847
+ sensor.full_resolution = 2400;
sensor.black_pixels = 96;
sensor.dummy_pixel = 26;
- sensor.ccd_start_xoffset = 128;
- sensor.sensor_pixels = 42720;
+ sensor.pixel_count_ratio = Ratio{1, 4};
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 230;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
@@ -2802,41 +2439,102 @@ void genesys_init_sensor_tables()
{ 0x5a, 0x40 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpihw;
+ unsigned shading_factor;
+ int output_pixel_offset;
+ };
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 600, 8, 4 },
+ { { 100 }, 600, 6, 5 },
+ { { 150 }, 600, 4, 8 },
+ { { 200 }, 600, 3, 10 },
+ { { 300 }, 600, 2, 16 },
+ { { 600 }, 600, 1, 32 },
+ { { 1200 }, 1200, 1, 64 },
+ { { 2400 }, 2400, 1, 128 },
+ };
+
+ auto base_custom_regs = sensor.custom_regs;
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpiset = setting.resolutions.values()[0];
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.shading_resolution = setting.register_dpihw;
+ sensor.shading_factor = setting.shading_factor;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CIS_CANON_LIDE_110;
- sensor.optical_res = 2400;
- sensor.ccd_size_divisor = 2;
+ sensor.sensor_id = SensorId::CIS_CANON_LIDE_110; // gl124
+ sensor.full_resolution = 2400;
sensor.black_pixels = 87;
sensor.dummy_pixel = 16;
- sensor.ccd_start_xoffset = 303;
- sensor.sensor_pixels = 5168*4;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
sensor.gamma = { 2.2f, 2.2f, 2.2f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_gl124;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpihw;
+ unsigned register_dpiset;
+ unsigned shading_resolution;
int exposure_lperiod;
SensorExposure exposure;
+ Ratio pixel_count_ratio;
+ unsigned shading_factor;
std::vector<unsigned> segment_order;
GenesysRegisterSettingSet custom_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 75, 100, 150 }, 4608, { 462, 609, 453 }, std::vector<unsigned>{}, {
+ { { 75 }, 1200, 600, 150, 300, 4608, { 462, 609, 453 }, Ratio{1, 4}, 4,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c },
+ { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 },
+ { 0x61, 0x20 },
+ { 0x70, 0x06 }, { 0x71, 0x08 }, { 0x72, 0x08 }, { 0x73, 0x0a },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x00 }, { 0x89, 0x65 },
+ { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 },
+ { 0x96, 0x00 }, { 0x97, 0x9a },
+ { 0x98, 0x21 },
+ }
+ },
+ { { 100 }, 1200, 600, 200, 300, 4608, { 462, 609, 453 }, Ratio{1, 4}, 3,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c },
+ { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 },
+ { 0x61, 0x20 },
+ { 0x70, 0x06 }, { 0x71, 0x08 }, { 0x72, 0x08 }, { 0x73, 0x0a },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x00 }, { 0x89, 0x65 },
+ { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 },
+ { 0x96, 0x00 }, { 0x97, 0x9a },
+ { 0x98, 0x21 },
+ }
+ },
+ { { 150 }, 1200, 600, 300, 300, 4608, { 462, 609, 453 }, Ratio{1, 4}, 2,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c },
{ 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
@@ -2853,7 +2551,8 @@ void genesys_init_sensor_tables()
{ 0x98, 0x21 },
}
},
- { { 300 }, 4608, { 462, 609, 453 }, std::vector<unsigned>{}, {
+ { { 300 }, 1200, 600, 600, 300, 4608, { 462, 609, 453 }, Ratio{1, 4}, 1,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x0c },
{ 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
@@ -2870,7 +2569,8 @@ void genesys_init_sensor_tables()
{ 0x98, 0x21 },
}
},
- { { 600 }, 5360, { 823, 1117, 805 }, std::vector<unsigned>{}, {
+ { { 600 }, 2400, 600, 600, 600, 5360, { 823, 1117, 805 }, Ratio{1, 4}, 1,
+ std::vector<unsigned>{}, {
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x0a },
{ 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
@@ -2887,7 +2587,8 @@ void genesys_init_sensor_tables()
{ 0x98, 0x21 },
},
},
- { { 1200 }, 10528, { 6071, 6670, 6042 }, { 0, 1 }, {
+ { { 1200 }, 2400, 1200, 1200, 1200, 10528, { 6071, 6670, 6042 }, Ratio{1, 4}, 1,
+ { 0, 1 }, {
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 },{ 0x20, 0x08 },
{ 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
@@ -2904,7 +2605,8 @@ void genesys_init_sensor_tables()
{ 0x98, 0x22 },
}
},
- { { 2400 }, 20864, { 7451, 8661, 7405 }, { 0, 2, 1, 3 }, {
+ { { 2400 }, 2400, 2400, 2400, 2400, 20864, { 7451, 8661, 7405 }, Ratio{1, 4}, 1,
+ { 0, 2, 1, 3 }, {
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x06 },
{ 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
@@ -2925,8 +2627,14 @@ void genesys_init_sensor_tables()
for (const auto& setting : custom_settings) {
sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.shading_resolution;
sensor.exposure_lperiod = setting.exposure_lperiod;
sensor.exposure = setting.exposure;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.shading_factor = setting.shading_factor;
sensor.segment_order = setting.segment_order;
sensor.custom_regs = setting.custom_regs;
s_sensors->push_back(sensor);
@@ -2934,34 +2642,69 @@ void genesys_init_sensor_tables()
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CIS_CANON_LIDE_120;
- sensor.optical_res = 2400;
- sensor.ccd_size_divisor = 2;
+ sensor.sensor_id = SensorId::CIS_CANON_LIDE_120; // gl124
+ sensor.full_resolution = 2400;
sensor.black_pixels = 87;
sensor.dummy_pixel = 16;
- sensor.ccd_start_xoffset = 303;
- // SEGCNT at 600 DPI by number of segments
- sensor.sensor_pixels = 5104*4;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
sensor.gamma = { 2.2f, 2.2f, 2.2f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_gl124;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpihw;
+ unsigned register_dpiset;
+ unsigned shading_resolution;
int exposure_lperiod;
SensorExposure exposure;
+ Ratio pixel_count_ratio;
+ unsigned shading_factor;
std::vector<unsigned> segment_order;
GenesysRegisterSettingSet custom_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 75, 100, 150, 300 }, 4608, { 1244, 1294, 1144 }, std::vector<unsigned>{}, {
+ { { 75 }, 1200, 600, 150, 300, 4608, { 1244, 1294, 1144 }, Ratio{1, 4}, 4,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x15 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x02 },
+ { 0x52, 0x04 }, { 0x53, 0x06 }, { 0x54, 0x00 }, { 0x55, 0x02 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x3a }, { 0x5b, 0x00 }, { 0x5c, 0x00 },
+ { 0x61, 0x20 },
+ { 0x70, 0x00 }, { 0x71, 0x1f }, { 0x72, 0x08 }, { 0x73, 0x0a },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x00 }, { 0x89, 0x5e },
+ { 0x93, 0x00 }, { 0x94, 0x09 }, { 0x95, 0xf8 },
+ { 0x96, 0x00 }, { 0x97, 0x70 },
+ { 0x98, 0x21 },
+ },
+ },
+ { { 100 }, 1200, 600, 200, 300, 4608, { 1244, 1294, 1144 }, Ratio{1, 4}, 3,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x15 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x02 },
+ { 0x52, 0x04 }, { 0x53, 0x06 }, { 0x54, 0x00 }, { 0x55, 0x02 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x3a }, { 0x5b, 0x00 }, { 0x5c, 0x00 },
+ { 0x61, 0x20 },
+ { 0x70, 0x00 }, { 0x71, 0x1f }, { 0x72, 0x08 }, { 0x73, 0x0a },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x00 }, { 0x89, 0x5e },
+ { 0x93, 0x00 }, { 0x94, 0x09 }, { 0x95, 0xf8 },
+ { 0x96, 0x00 }, { 0x97, 0x70 },
+ { 0x98, 0x21 },
+ },
+ },
+ { { 150 }, 1200, 600, 300, 300, 4608, { 1244, 1294, 1144 }, Ratio{1, 4}, 2,
+ std::vector<unsigned>{}, {
{ 0x16, 0x15 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x02 },
{ 0x52, 0x04 }, { 0x53, 0x06 }, { 0x54, 0x00 }, { 0x55, 0x02 },
@@ -2978,7 +2721,26 @@ void genesys_init_sensor_tables()
{ 0x98, 0x21 },
},
},
- { { 600 }, 5360, { 2394, 2444, 2144 }, std::vector<unsigned>{}, {
+ { { 300 }, 1200, 600, 600, 300, 4608, { 1244, 1294, 1144 }, Ratio{1, 4}, 1,
+ std::vector<unsigned>{}, {
+ { 0x16, 0x15 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x02 },
+ { 0x52, 0x04 }, { 0x53, 0x06 }, { 0x54, 0x00 }, { 0x55, 0x02 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x3a }, { 0x5b, 0x00 }, { 0x5c, 0x00 },
+ { 0x61, 0x20 },
+ { 0x70, 0x00 }, { 0x71, 0x1f }, { 0x72, 0x08 }, { 0x73, 0x0a },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x00 }, { 0x89, 0x5e },
+ { 0x93, 0x00 }, { 0x94, 0x09 }, { 0x95, 0xf8 },
+ { 0x96, 0x00 }, { 0x97, 0x70 },
+ { 0x98, 0x21 },
+ },
+ },
+ { { 600 }, 2400, 600, 600, 600, 5360, { 2394, 2444, 2144 }, Ratio{1, 4}, 1,
+ std::vector<unsigned>{}, {
{ 0x16, 0x11 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x02 },
{ 0x52, 0x04 }, { 0x53, 0x06 }, { 0x54, 0x00 }, { 0x55, 0x02 },
@@ -2995,7 +2757,8 @@ void genesys_init_sensor_tables()
{ 0x98, 0x21 },
},
},
- { { 1200 }, 10528, { 4694, 4644, 4094 }, std::vector<unsigned>{}, {
+ { { 1200 }, 2400, 1200, 1200, 1200, 10528, { 4694, 4644, 4094 }, Ratio{1, 2}, 1,
+ std::vector<unsigned>{}, {
{ 0x16, 0x15 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x02 },
{ 0x52, 0x04 }, { 0x53, 0x06 }, { 0x54, 0x00 }, { 0x55, 0x02 },
@@ -3012,7 +2775,8 @@ void genesys_init_sensor_tables()
{ 0x98, 0x21 },
},
},
- { { 2400 }, 20864, { 8944, 8144, 7994 }, std::vector<unsigned>{}, {
+ { { 2400 }, 2400, 2400, 2400, 2400, 20864, { 8944, 8144, 7994 }, Ratio{1, 1}, 1,
+ std::vector<unsigned>{}, {
{ 0x16, 0x11 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x02 },
{ 0x52, 0x04 }, { 0x53, 0x06 }, { 0x54, 0x00 }, { 0x55, 0x02 },
@@ -3033,8 +2797,14 @@ void genesys_init_sensor_tables()
for (const auto& setting : custom_settings) {
sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.shading_resolution;
sensor.exposure_lperiod = setting.exposure_lperiod;
sensor.exposure = setting.exposure;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.shading_factor = setting.shading_factor;
sensor.segment_order = setting.segment_order;
sensor.custom_regs = setting.custom_regs;
s_sensors->push_back(sensor);
@@ -3042,33 +2812,71 @@ void genesys_init_sensor_tables()
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CIS_CANON_LIDE_210;
- sensor.optical_res = 2400;
- sensor.ccd_size_divisor = 2;
+ sensor.sensor_id = SensorId::CIS_CANON_LIDE_210; // gl124
+ sensor.full_resolution = 4800;
sensor.black_pixels = 87;
sensor.dummy_pixel = 16;
- sensor.ccd_start_xoffset = 303;
- sensor.sensor_pixels = 5168*4;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
sensor.gamma = { 2.2f, 2.2f, 2.2f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_gl124;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpihw;
+ unsigned register_dpiset;
+ unsigned shading_resolution;
int exposure_lperiod;
SensorExposure exposure;
+ Ratio pixel_count_ratio;
+ unsigned shading_factor;
std::vector<unsigned> segment_order;
GenesysRegisterSettingSet custom_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 75, 100, 150, 300 }, 2768, { 388, 574, 393 }, std::vector<unsigned>{}, {
+ { { 75 }, 2400, 600, 150, 300, 2768, { 388, 574, 393 }, Ratio{1, 8}, 4,
+ std::vector<unsigned>{}, {
+ // { 0x16, 0x00 }, // FIXME: check if default value is different
+ { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c },
+ { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 },
+ { 0x61, 0x20 },
+ // { 0x70, 0x00 }, // FIXME: check if default value is different
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x00 }, { 0x89, 0x65 },
+ { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 },
+ { 0x96, 0x00 }, { 0x97, 0x9a },
+ { 0x98, 0x21 },
+ }
+ },
+ { { 100 }, 2400, 600, 200, 300, 2768, { 388, 574, 393 }, Ratio{1, 8}, 3,
+ std::vector<unsigned>{}, {
+ // { 0x16, 0x00 }, // FIXME: check if default value is different
+ { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c },
+ { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 },
+ { 0x61, 0x20 },
+ // { 0x70, 0x00 }, // FIXME: check if default value is different
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x00 }, { 0x89, 0x65 },
+ { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 },
+ { 0x96, 0x00 }, { 0x97, 0x9a },
+ { 0x98, 0x21 },
+ }
+ },
+ { { 150 }, 2400, 600, 300, 300, 2768, { 388, 574, 393 }, Ratio{1, 8}, 2,
+ std::vector<unsigned>{}, {
// { 0x16, 0x00 }, // FIXME: check if default value is different
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c },
@@ -3086,7 +2894,27 @@ void genesys_init_sensor_tables()
{ 0x98, 0x21 },
}
},
- { { 600 }, 5360, { 388, 574, 393 }, std::vector<unsigned>{}, {
+ { { 300 }, 2400, 600, 600, 300, 2768, { 388, 574, 393 }, Ratio{1, 8}, 1,
+ std::vector<unsigned>{}, {
+ // { 0x16, 0x00 }, // FIXME: check if default value is different
+ { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c },
+ { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 },
+ { 0x61, 0x20 },
+ // { 0x70, 0x00 }, // FIXME: check if default value is different
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x00 }, { 0x89, 0x65 },
+ { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 },
+ { 0x96, 0x00 }, { 0x97, 0x9a },
+ { 0x98, 0x21 },
+ }
+ },
+ { { 600 }, 4800, 600, 600, 600, 5360, { 388, 574, 393 }, Ratio{1, 8}, 1,
+ std::vector<unsigned>{}, {
// { 0x16, 0x00 }, // FIXME: check if default value is different
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0a },
@@ -3104,7 +2932,7 @@ void genesys_init_sensor_tables()
{ 0x98, 0x21 },
}
},
- { { 1200 }, 10528, { 388, 574, 393 }, {0, 1}, {
+ { { 1200 }, 4800, 1200, 1200, 1200, 10528, { 388, 574, 393 }, Ratio{1, 8}, 1, {0, 1}, {
// { 0x16, 0x00 }, // FIXME: check if default value is different
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x08 },
@@ -3122,7 +2950,8 @@ void genesys_init_sensor_tables()
{ 0x98, 0x22 },
},
},
- { { 2400 }, 20864, { 6839, 8401, 6859 }, {0, 2, 1, 3}, {
+ { { 2400 }, 4800, 2400, 2400, 2400, 20864, { 6839, 8401, 6859 }, Ratio{1, 8}, 1,
+ {0, 2, 1, 3}, {
// { 0x16, 0x00 }, // FIXME: check if default value is different
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x06 },
@@ -3139,13 +2968,38 @@ void genesys_init_sensor_tables()
{ 0x96, 0x00 }, { 0x97, 0xa3 },
{ 0x98, 0x24 },
},
+ },
+ { { 4800 }, 4800, 4800, 4800, 4800, 41536, { 9735, 14661, 11345 }, Ratio{1, 8}, 1,
+ { 0, 2, 4, 6, 1, 3, 5, 7 }, {
+ // { 0x16, 0x00 }, // FIXME: check if default value is different
+ { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x04 },
+ { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 },
+ { 0x61, 0x20 },
+ // { 0x70, 0x00 }, // FIXME: check if default value is different
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x12 }, { 0x89, 0x47 },
+ { 0x93, 0x00 }, { 0x94, 0x14 }, { 0x95, 0x30 },
+ { 0x96, 0x00 }, { 0x97, 0xa5 },
+ { 0x98, 0x28 },
+ },
}
};
for (const auto& setting : custom_settings) {
sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.shading_resolution;
sensor.exposure_lperiod = setting.exposure_lperiod;
sensor.exposure = setting.exposure;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.shading_factor = setting.shading_factor;
sensor.segment_order = setting.segment_order;
sensor.custom_regs = setting.custom_regs;
s_sensors->push_back(sensor);
@@ -3153,33 +3007,33 @@ void genesys_init_sensor_tables()
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CIS_CANON_LIDE_220;
- sensor.optical_res = 2400;
- sensor.ccd_size_divisor = 2;
+ sensor.sensor_id = SensorId::CIS_CANON_LIDE_220; // gl124
+ sensor.full_resolution = 4800;
sensor.black_pixels = 87;
sensor.dummy_pixel = 16;
- sensor.ccd_start_xoffset = 303;
- sensor.sensor_pixels = 5168*4;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
sensor.gamma = { 2.2f, 2.2f, 2.2f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_gl124;
{
struct CustomSensorSettings {
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpihw;
+ unsigned register_dpiset;
+ unsigned shading_resolution;
int exposure_lperiod;
SensorExposure exposure;
+ Ratio pixel_count_ratio;
+ unsigned shading_factor;
std::vector<unsigned> segment_order;
GenesysRegisterSettingSet custom_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 75, 100, 150, 300 }, 2768, { 388, 574, 393 }, std::vector<unsigned>{}, {
+ { { 75 }, 2400, 600, 150, 300, 2768, { 388, 574, 393 }, Ratio{1, 8}, 4,
+ std::vector<unsigned>{}, {
// { 0x16, 0x00 }, // FIXME: check if default value is different
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c },
@@ -3197,7 +3051,65 @@ void genesys_init_sensor_tables()
{ 0x98, 0x21 },
}
},
- { { 600 }, 5360, { 388, 574, 393 }, std::vector<unsigned>{}, {
+ { { 100 }, 2400, 600, 200, 300, 2768, { 388, 574, 393 }, Ratio{1, 8}, 3,
+ std::vector<unsigned>{}, {
+ // { 0x16, 0x00 }, // FIXME: check if default value is different
+ { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c },
+ { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 },
+ { 0x61, 0x20 },
+ // { 0x70, 0x00 }, // FIXME: check if default value is different
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x00 }, { 0x89, 0x65 },
+ { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 },
+ { 0x96, 0x00 }, { 0x97, 0x9a },
+ { 0x98, 0x21 },
+ }
+ },
+ { { 150 }, 2400, 600, 300, 300, 2768, { 388, 574, 393 }, Ratio{1, 8}, 2,
+ std::vector<unsigned>{}, {
+ // { 0x16, 0x00 }, // FIXME: check if default value is different
+ { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c },
+ { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 },
+ { 0x61, 0x20 },
+ // { 0x70, 0x00 }, // FIXME: check if default value is different
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x00 }, { 0x89, 0x65 },
+ { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 },
+ { 0x96, 0x00 }, { 0x97, 0x9a },
+ { 0x98, 0x21 },
+ }
+ },
+ { { 300 }, 2400, 600, 600, 300, 2768, { 388, 574, 393 }, Ratio{1, 8}, 1,
+ std::vector<unsigned>{}, {
+ // { 0x16, 0x00 }, // FIXME: check if default value is different
+ { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c },
+ { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 },
+ { 0x61, 0x20 },
+ // { 0x70, 0x00 }, // FIXME: check if default value is different
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x00 }, { 0x89, 0x65 },
+ { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 },
+ { 0x96, 0x00 }, { 0x97, 0x9a },
+ { 0x98, 0x21 },
+ }
+ },
+ { { 600 }, 4800, 600, 600, 600, 5360, { 388, 574, 393 }, Ratio{1, 8}, 1,
+ std::vector<unsigned>{}, {
// { 0x16, 0x00 }, // FIXME: check if default value is different
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0a },
@@ -3215,7 +3127,8 @@ void genesys_init_sensor_tables()
{ 0x98, 0x21 },
}
},
- { { 1200 }, 10528, { 388, 574, 393 }, {0, 1}, {
+ { { 1200 }, 4800, 1200, 1200, 1200, 10528, { 388, 574, 393 }, Ratio{1, 8}, 1,
+ {0, 1}, {
// { 0x16, 0x00 }, // FIXME: check if default value is different
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x08 },
@@ -3233,7 +3146,8 @@ void genesys_init_sensor_tables()
{ 0x98, 0x22 },
}
},
- { { 2400 }, 20864, { 6839, 8401, 6859 }, {0, 2, 1, 3}, {
+ { { 2400 }, 4800, 2400, 2400, 2400, 20864, { 6839, 8401, 6859 }, Ratio{1, 8}, 1,
+ {0, 2, 1, 3}, {
// { 0x16, 0x00 }, // FIXME: check if default value is different
{ 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
{ 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x06 },
@@ -3250,13 +3164,38 @@ void genesys_init_sensor_tables()
{ 0x96, 0x00 }, { 0x97, 0xa3 },
{ 0x98, 0x24 },
},
+ },
+ { { 4800 }, 4800, 4800, 4800, 4800, 41536, { 9735, 14661, 11345 }, Ratio{1, 8}, 1,
+ { 0, 2, 4, 6, 1, 3, 5, 7 }, {
+ // { 0x16, 0x00 }, // FIXME: check if default value is different
+ { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 },
+ { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x04 },
+ { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 },
+ { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 },
+ { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 },
+ { 0x61, 0x20 },
+ // { 0x70, 0x00 }, // FIXME: check if default value is different
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x88, 0x12 }, { 0x89, 0x47 },
+ { 0x93, 0x00 }, { 0x94, 0x14 }, { 0x95, 0x30 },
+ { 0x96, 0x00 }, { 0x97, 0xa5 },
+ { 0x98, 0x28 },
+ },
}
};
for (const auto& setting : custom_settings) {
sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.shading_resolution;
sensor.exposure_lperiod = setting.exposure_lperiod;
sensor.exposure = setting.exposure;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.shading_factor = setting.shading_factor;
sensor.segment_order = setting.segment_order;
sensor.custom_regs = setting.custom_regs;
s_sensors->push_back(sensor);
@@ -3264,63 +3203,116 @@ void genesys_init_sensor_tables()
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICPRO_3600;
- sensor.optical_res = 1200;
- sensor.ccd_size_divisor = 2;
+ sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICPRO_3600; // gl841
+ sensor.full_resolution = 1200;
sensor.black_pixels = 87;
sensor.dummy_pixel = 87;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10100;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 230;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
sensor.custom_regs = {
- { 0x08, 0x00 },
- { 0x09, 0x00 },
- { 0x0a, 0x00 },
- { 0x0b, 0x00 },
- { 0x16, 0x33 },
- { 0x17, 0x0b },
- { 0x18, 0x11 },
- { 0x19, 0x2a },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0xc4 },
- { 0x52, 0x07 }, // [GB](HI|LOW) not needed for cis
- { 0x53, 0x0a },
- { 0x54, 0x0c },
- { 0x55, 0x00 },
- { 0x56, 0x02 },
- { 0x57, 0x06 },
- { 0x58, 0x22 },
- { 0x59, 0x69 },
- { 0x5a, 0x40 },
- { 0x5b, 0x00 }, // TODO: 5b-5e
- { 0x5c, 0x00 },
- { 0x5d, 0x00 },
- { 0x5e, 0x02 },
+ { 0x16, 0x33 }, { 0x17, 0x0b }, { 0x18, 0x11 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0xc4 },
+ { 0x52, 0x07 }, { 0x53, 0x0a }, { 0x54, 0x0c }, { 0x55, 0x00 },
+ { 0x56, 0x02 }, { 0x57, 0x06 }, { 0x58, 0x22 }, { 0x59, 0x69 }, { 0x5a, 0x40 },
+ { 0x70, 0x00 }, { 0x71, 0x00 }, { 0x72, 0x00 }, { 0x73, 0x00 },
+ };
+ sensor.gamma = { 1.0f, 1.0f, 1.0f };
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpihw;
+ unsigned register_dpiset;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 600, 600, 150, 11 },
+ { { 100 }, 600, 600, 200, 14 },
+ { { 150 }, 600, 600, 300, 22 },
+ { { 200 }, 600, 600, 400, 29 },
+ { { 300 }, 600, 600, 600, 44 },
+ { { 600 }, 600, 600, 1200, 88 },
+ { { 1200 }, 1200, 1200, 1200, 88 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.register_dpihw;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
+
+
+ sensor = Genesys_Sensor();
+ sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7200; // gl842
+ sensor.full_resolution = 7200;
+ sensor.register_dpihw = 1200;
+ sensor.black_pixels = 88; // TODO
+ sensor.dummy_pixel = 19;
+ sensor.fau_gain_white_ref = 210;
+ sensor.gain_white_ref = 230;
+ sensor.exposure = { 0x2b00, 0x2b00, 0x2b00 };
+ sensor.exposure_lperiod = 0x694e;
+ sensor.use_host_side_calib = true;
+ sensor.custom_regs = {
+ { 0x16, 0x3b }, { 0x17, 0x4b }, { 0x18, 0x10 }, { 0x19, 0x00 },
+ { 0x1a, 0x24 }, { 0x1b, 0x00 }, { 0x1c, 0x40 }, { 0x1d, 0x84 },
+ { 0x52, 0x09 }, { 0x53, 0x0c }, { 0x54, 0x0e }, { 0x55, 0x02 },
+ { 0x56, 0x04 }, { 0x57, 0x07 }, { 0x58, 0x22 }, { 0x59, 0x69 }, { 0x5a, 0xc0 },
+ { 0x70, 0x08 }, { 0x71, 0x09 }, { 0x72, 0x0b }, { 0x73, 0x0c },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 },
+ { 0x77, 0x00 }, { 0x78, 0x7f }, { 0x79, 0xff },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, { 0x7d, 0x00 }, { 0x7f, 0x01 }
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ ScanMethod method;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
+ unsigned register_dpiset;
+ StaggerConfig stagger_y;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 900 }, ScanMethod::TRANSPARENCY, Ratio{8, 8}, 2, 150, StaggerConfig{} },
+ { { 1800 }, ScanMethod::TRANSPARENCY, Ratio{4, 4}, 10, 300, StaggerConfig{} },
+ { { 3600 }, ScanMethod::TRANSPARENCY, Ratio{2, 2}, 10, 600, StaggerConfig{} },
+ { { 7200 }, ScanMethod::TRANSPARENCY, Ratio{1, 1}, 20, 1200, StaggerConfig{0, 4} },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.method = setting.method;
+ sensor.shading_resolution = setting.resolutions.values().front();
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.stagger_y = setting.stagger_y;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7200I;
- sensor.optical_res = 7200;
- sensor.register_dpihw_override = 1200;
+ sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7200I; // gl843
+ sensor.full_resolution = 7200;
+ sensor.register_dpihw = 1200;
sensor.black_pixels = 88; // TODO
sensor.dummy_pixel = 20;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10200; // TODO
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 230;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
- sensor.stagger_config = StaggerConfig{7200, 4};
+ sensor.use_host_side_calib = true;
sensor.custom_regs = {
{ 0x08, 0x00 },
{ 0x09, 0x00 },
@@ -3351,47 +3343,53 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact;
{
struct CustomSensorSettings
{
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
ScanMethod method;
- unsigned ccd_size_divisor;
- unsigned logical_dpihw_override;
- unsigned pixel_count_multiplier;
+ unsigned shading_resolution;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
unsigned exposure_lperiod;
- unsigned dpiset_override;
+ unsigned register_dpiset;
+ StaggerConfig stagger_y;
GenesysRegisterSettingSet custom_fe_regs;
};
CustomSensorSettings custom_settings[] = {
- { { 900 }, ScanMethod::TRANSPARENCY, 1, 900, 8, 0x2538, 150, {} },
- { { 1800 }, ScanMethod::TRANSPARENCY, 1, 1800, 4, 0x2538, 300, {} },
- { { 3600 }, ScanMethod::TRANSPARENCY, 1, 3600, 2, 0x2538, 600, {} },
- { { 7200 }, ScanMethod::TRANSPARENCY, 1, 7200, 1, 0x19c8, 1200, {
+ { { 900 }, ScanMethod::TRANSPARENCY, 900, Ratio{8, 8}, 2, 0x2538, 150,
+ StaggerConfig{}, {} },
+ { { 1800 }, ScanMethod::TRANSPARENCY, 1800, Ratio{4, 4}, 5, 0x2538, 300,
+ StaggerConfig{}, {} },
+ { { 3600 }, ScanMethod::TRANSPARENCY, 3600, Ratio{2, 2}, 10, 0x2538, 600,
+ StaggerConfig{}, {} },
+ { { 7200 }, ScanMethod::TRANSPARENCY, 7200, Ratio{1, 1}, 20, 0x19c8, 1200,
+ StaggerConfig{4, 0}, {
{ 0x02, 0x1b },
{ 0x03, 0x14 },
{ 0x04, 0x20 },
}
},
- { { 900 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 900, 8, 0x1f54, 150, {} },
- { { 1800 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 1800, 4, 0x1f54, 300, {} },
- { { 3600 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 3600, 2, 0x1f54, 600, {} },
- { { 7200 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 7200, 1, 0x1f54, 1200, {} },
+ { { 900 }, ScanMethod::TRANSPARENCY_INFRARED, 900, Ratio{8, 8}, 2, 0x1f54, 150,
+ StaggerConfig{}, {} },
+ { { 1800 }, ScanMethod::TRANSPARENCY_INFRARED, 1800, Ratio{4, 4}, 5, 0x1f54, 300,
+ StaggerConfig{}, {} },
+ { { 3600 }, ScanMethod::TRANSPARENCY_INFRARED, 3600, Ratio{2, 2}, 10, 0x1f54, 600,
+ StaggerConfig{}, {}},
+ { { 7200 }, ScanMethod::TRANSPARENCY_INFRARED, 7200, Ratio{1, 1}, 20, 0x1f54, 1200,
+ StaggerConfig{4, 0}, {} },
};
for (const CustomSensorSettings& setting : custom_settings) {
sensor.resolutions = setting.resolutions;
sensor.method = setting.method;
- sensor.ccd_size_divisor = setting.ccd_size_divisor;
- sensor.logical_dpihw_override = setting.logical_dpihw_override;
- sensor.pixel_count_multiplier = setting.pixel_count_multiplier;
+ sensor.shading_resolution = setting.shading_resolution;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
sensor.exposure_lperiod = setting.exposure_lperiod;
- sensor.dpiset_override = setting.dpiset_override;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.stagger_y = setting.stagger_y;
sensor.custom_fe_regs = setting.custom_fe_regs;
s_sensors->push_back(sensor);
}
@@ -3399,19 +3397,17 @@ void genesys_init_sensor_tables()
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7300;
- sensor.optical_res = 7200;
+ sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7300; // gl843
+ sensor.full_resolution = 7200;
sensor.method = ScanMethod::TRANSPARENCY;
- sensor.register_dpihw_override = 1200;
+ sensor.register_dpihw = 1200;
sensor.black_pixels = 88; // TODO
sensor.dummy_pixel = 20;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10200; // TODO
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 230;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
sensor.exposure_lperiod = 0x2f44;
- sensor.stagger_config = StaggerConfig{7200, 4};
+ sensor.use_host_side_calib = true;
sensor.custom_regs = {
{ 0x08, 0x00 },
{ 0x09, 0x00 },
@@ -3442,50 +3438,98 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact;
{
struct CustomSensorSettings
{
- ResolutionFilter resolutions;
- unsigned ccd_size_divisor;
- unsigned logical_dpihw_override;
- unsigned pixel_count_multiplier;
- unsigned dpiset_override;
+ ValueFilterAny<unsigned> resolutions;
+ unsigned shading_resolution;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
+ unsigned register_dpiset;
+ StaggerConfig stagger_y;
};
CustomSensorSettings custom_settings[] = {
- { { 900 }, 1, 900, 8, 150 },
- { { 1800 }, 1, 1800, 4, 300 },
- { { 3600 }, 1, 3600, 2, 600 },
- { { 7200 }, 1, 7200, 1, 1200 },
+ { { 900 }, 900, Ratio{8, 8}, 2, 150, StaggerConfig{} },
+ { { 1800 }, 1800, Ratio{4, 4}, 5, 300, StaggerConfig{} },
+ { { 3600 }, 3600, Ratio{2, 2}, 10, 600, StaggerConfig{} },
+ { { 7200 }, 7200, Ratio{1, 1}, 20, 1200, StaggerConfig{4, 0} },
};
for (const CustomSensorSettings& setting : custom_settings) {
sensor.resolutions = setting.resolutions;
- sensor.ccd_size_divisor = setting.ccd_size_divisor;
- sensor.logical_dpihw_override = setting.logical_dpihw_override;
- sensor.pixel_count_multiplier = setting.pixel_count_multiplier;
- sensor.dpiset_override = setting.dpiset_override;
+ sensor.shading_resolution = setting.shading_resolution;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.stagger_y = setting.stagger_y;
s_sensors->push_back(sensor);
}
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7500I;
- sensor.optical_res = 7200;
- sensor.register_dpihw_override = 1200;
+ sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7400; // gl845
+ sensor.full_resolution = 7200;
+ sensor.method = ScanMethod::TRANSPARENCY;
+ sensor.register_dpihw = 1200;
sensor.black_pixels = 88; // TODO
sensor.dummy_pixel = 20;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10200; // TODO
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 230;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
- sensor.stagger_config = StaggerConfig{7200, 4};
+ sensor.exposure_lperiod = 14000;
+ sensor.use_host_side_calib = true;
+ sensor.custom_regs = {
+ { 0x08, 0x00 }, { 0x09, 0x00 }, { 0x0a, 0x00 },
+ { 0x16, 0x27 }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x84 },
+ { 0x52, 0x09 }, { 0x53, 0x0d }, { 0x54, 0x0f }, { 0x55, 0x01 },
+ { 0x56, 0x04 }, { 0x57, 0x07 }, { 0x58, 0x31 }, { 0x59, 0x79 }, { 0x5a, 0xc0 },
+ { 0x70, 0x0a }, { 0x71, 0x0b }, { 0x72, 0x0c }, { 0x73, 0x0d },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, { 0x7d, 0x00 },
+ { 0x87, 0x00 },
+ };
+ sensor.gamma = { 1.0f, 1.0f, 1.0f };
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpiset;
+ int output_pixel_offset;
+ StaggerConfig stagger_y;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 600 }, 100, 10, StaggerConfig{} },
+ { { 1200 }, 200, 20, StaggerConfig{} },
+ { { 2400 }, 400, 40, StaggerConfig{} },
+ { { 3600 }, 600, 60, StaggerConfig{} },
+ { { 7200 }, 1200, 120, StaggerConfig{4, 0} },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.shading_resolution = setting.resolutions.values()[0];
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.stagger_y = setting.stagger_y;
+ s_sensors->push_back(sensor);
+ }
+ }
+
+ sensor = Genesys_Sensor();
+ sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7500I; // gl843
+ sensor.full_resolution = 7200;
+ sensor.register_dpihw = 1200;
+ sensor.black_pixels = 88; // TODO
+ sensor.dummy_pixel = 20;
+ sensor.fau_gain_white_ref = 210;
+ sensor.gain_white_ref = 230;
+ sensor.exposure = { 0x0000, 0x0000, 0x0000 };
+ sensor.use_host_side_calib = true;
sensor.custom_regs = {
{ 0x08, 0x00 },
{ 0x09, 0x00 },
@@ -3516,57 +3560,119 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact;
{
struct CustomSensorSettings
{
- ResolutionFilter resolutions;
+ ValueFilterAny<unsigned> resolutions;
ScanMethod method;
- unsigned ccd_size_divisor;
- unsigned logical_dpihw_override;
- unsigned pixel_count_multiplier;
+ unsigned shading_resolution;
+ Ratio pixel_count_ratio;
+ int output_pixel_offset;
unsigned exposure_lperiod;
- unsigned dpiset_override;
+ unsigned register_dpiset;
+ StaggerConfig stagger_y;
};
CustomSensorSettings custom_settings[] = {
- { { 900 }, ScanMethod::TRANSPARENCY, 1, 900, 8, 0x2f44, 150 },
- { { 1800 }, ScanMethod::TRANSPARENCY, 1, 1800, 4, 0x2f44, 300 },
- { { 3600 }, ScanMethod::TRANSPARENCY, 1, 3600, 2, 0x2f44, 600 },
- { { 7200 }, ScanMethod::TRANSPARENCY, 1, 7200, 1, 0x2f44, 1200 },
- { { 900 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 900, 8, 0x2af8, 150 },
- { { 1800 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 1800, 4, 0x2af8, 300 },
- { { 3600 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 3600, 2, 0x2af8, 600 },
- { { 7200 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 7200, 1, 0x2af8, 1200 },
+ { { 900 }, ScanMethod::TRANSPARENCY, 900, Ratio{8, 8}, 2, 0x2f44, 150,
+ StaggerConfig{} },
+ { { 1800 }, ScanMethod::TRANSPARENCY, 1800, Ratio{4, 4}, 5, 0x2f44, 300,
+ StaggerConfig{} },
+ { { 3600 }, ScanMethod::TRANSPARENCY, 3600, Ratio{2, 2}, 10, 0x2f44, 600,
+ StaggerConfig{} },
+ { { 7200 }, ScanMethod::TRANSPARENCY, 7200, Ratio{1, 1}, 20, 0x2f44, 1200,
+ StaggerConfig{4, 0} },
+ { { 900 }, ScanMethod::TRANSPARENCY_INFRARED, 900, Ratio{8, 8}, 2, 0x2af8, 150,
+ StaggerConfig{} },
+ { { 1800 }, ScanMethod::TRANSPARENCY_INFRARED, 1800, Ratio{4, 4}, 5, 0x2af8, 300,
+ StaggerConfig{} },
+ { { 3600 }, ScanMethod::TRANSPARENCY_INFRARED, 3600, Ratio{2, 2}, 10, 0x2af8, 600,
+ StaggerConfig{} },
+ { { 7200 }, ScanMethod::TRANSPARENCY_INFRARED, 7200, Ratio{1, 1}, 20, 0x2af8, 1200,
+ StaggerConfig{4, 0} },
};
for (const CustomSensorSettings& setting : custom_settings) {
sensor.resolutions = setting.resolutions;
sensor.method = setting.method;
- sensor.ccd_size_divisor = setting.ccd_size_divisor;
- sensor.logical_dpihw_override = setting.logical_dpihw_override;
- sensor.pixel_count_multiplier = setting.pixel_count_multiplier;
+ sensor.shading_resolution = setting.shading_resolution;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
sensor.exposure_lperiod = setting.exposure_lperiod;
- sensor.dpiset_override = setting.dpiset_override;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.stagger_y = setting.stagger_y;
s_sensors->push_back(sensor);
}
}
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_IMG101;
+ sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_8200I; // gl845
+ sensor.full_resolution = 7200;
+ sensor.method = ScanMethod::TRANSPARENCY;
+ sensor.register_dpihw = 1200;
+ sensor.black_pixels = 88; // TODO
+ sensor.dummy_pixel = 20;
+ sensor.fau_gain_white_ref = 210;
+ sensor.gain_white_ref = 230;
+ sensor.exposure = { 0x0000, 0x0000, 0x0000 };
+ sensor.exposure_lperiod = 14000;
+ sensor.use_host_side_calib = true;
+ sensor.custom_regs = {
+ { 0x08, 0x00 }, { 0x09, 0x00 }, { 0x0a, 0x00 },
+ { 0x16, 0x27 }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x84 },
+ { 0x52, 0x09 }, { 0x53, 0x0d }, { 0x54, 0x0f }, { 0x55, 0x01 },
+ { 0x56, 0x04 }, { 0x57, 0x07 }, { 0x58, 0x31 }, { 0x59, 0x79 }, { 0x5a, 0xc0 },
+ { 0x70, 0x0a }, { 0x71, 0x0b }, { 0x72, 0x0c }, { 0x73, 0x0d },
+ { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 },
+ { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, { 0x7d, 0x00 },
+ { 0x87, 0x00 },
+ };
+ sensor.gamma = { 1.0f, 1.0f, 1.0f };
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ ScanMethod method;
+ unsigned register_dpiset;
+ int output_pixel_offset;
+ StaggerConfig stagger_y;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 900 }, ScanMethod::TRANSPARENCY, 150, 15, StaggerConfig{} },
+ { { 1800 }, ScanMethod::TRANSPARENCY, 300, 30, StaggerConfig{} },
+ { { 3600 }, ScanMethod::TRANSPARENCY, 600, 60, StaggerConfig{} },
+ { { 7200 }, ScanMethod::TRANSPARENCY, 1200, 120, StaggerConfig{4, 0} },
+ { { 900 }, ScanMethod::TRANSPARENCY_INFRARED, 150, 15, StaggerConfig{} },
+ { { 1800 }, ScanMethod::TRANSPARENCY_INFRARED, 300, 30, StaggerConfig{} },
+ { { 3600 }, ScanMethod::TRANSPARENCY_INFRARED, 600, 60, StaggerConfig{} },
+ { { 7200 }, ScanMethod::TRANSPARENCY_INFRARED, 1200, 120, StaggerConfig{4, 0} },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.method = setting.method;
+ sensor.shading_resolution = setting.resolutions.values()[0];
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ sensor.stagger_y = setting.stagger_y;
+ s_sensors->push_back(sensor);
+ }
+ }
+
+
+ sensor = Genesys_Sensor();
+ sensor.sensor_id = SensorId::CCD_IMG101; // gl846
sensor.resolutions = { 75, 100, 150, 300, 600, 1200 };
sensor.exposure_lperiod = 11000;
sensor.segment_size = 5136;
sensor.segment_order = {0, 1};
- sensor.optical_res = 1200;
+ sensor.full_resolution = 1200;
sensor.black_pixels = 31;
sensor.dummy_pixel = 31;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10800;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0x0000, 0x0000, 0x0000 };
@@ -3580,21 +3686,47 @@ void genesys_init_sensor_tables()
{ 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
};
sensor.gamma = { 1.7f, 1.7f, 1.7f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpihw;
+ Ratio pixel_count_ratio;
+ unsigned shading_factor;
+ GenesysRegisterSettingSet extra_custom_regs;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 600, Ratio{1, 4}, 8, { { 0x7e, 0x00 } } },
+ { { 100 }, 600, Ratio{1, 4}, 6, { { 0x7e, 0x00 } } },
+ { { 150 }, 600, Ratio{1, 4}, 4, { { 0x7e, 0x00 } } },
+ { { 300 }, 600, Ratio{1, 4}, 2, { { 0x7e, 0x00 } } },
+ { { 600 }, 600, Ratio{1, 4}, 1, { { 0x7e, 0x01 } } },
+ { { 1200 }, 1200, Ratio{1, 2}, 1, { { 0x7e, 0x01 } } },
+ };
+
+ auto base_custom_regs = sensor.custom_regs;
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.resolutions.values()[0];
+ sensor.shading_resolution = setting.register_dpihw;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.shading_factor = setting.shading_factor;
+ sensor.custom_regs = base_custom_regs;
+ sensor.custom_regs.merge(setting.extra_custom_regs);
+ s_sensors->push_back(sensor);
+ }
+ }
+
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICBOOK_3800;
+ sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICBOOK_3800; // gl845
sensor.resolutions = { 75, 100, 150, 300, 600, 1200 };
sensor.exposure_lperiod = 11000;
- sensor.optical_res = 1200;
+ sensor.full_resolution = 1200;
sensor.black_pixels = 31;
sensor.dummy_pixel = 31;
- sensor.ccd_start_xoffset = 0;
- sensor.sensor_pixels = 10200;
sensor.fau_gain_white_ref = 210;
sensor.gain_white_ref = 200;
sensor.exposure = { 0, 0, 0 };
@@ -3603,66 +3735,150 @@ void genesys_init_sensor_tables()
{ 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x06 },
{ 0x52, 0x02 }, { 0x53, 0x04 }, { 0x54, 0x06 }, { 0x55, 0x08 },
{ 0x56, 0x0a }, { 0x57, 0x00 }, { 0x58, 0x59 }, { 0x59, 0x31 }, { 0x5a, 0x40 },
+ { 0x70, 0x01 }, { 0x71, 0x00 }, { 0x72, 0x02 }, { 0x73, 0x01 },
{ 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c },
{ 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f },
- { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 },
+ { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, { 0x7d, 0x20 },
+ { 0x87, 0x02 },
};
sensor.gamma = { 1.7f, 1.7f, 1.7f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned register_dpihw;
+ Ratio pixel_count_ratio;
+ unsigned shading_factor;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 600, Ratio{1, 2}, 8 },
+ { { 100 }, 600, Ratio{1, 2}, 6 },
+ { { 150 }, 600, Ratio{1, 2}, 4 },
+ { { 300 }, 600, Ratio{1, 2}, 2 },
+ { { 600 }, 600, Ratio{1, 2}, 1 },
+ { { 1200 }, 1200, Ratio{1, 1}, 1 },
+ };
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.register_dpihw = setting.register_dpihw;
+ sensor.register_dpiset = setting.resolutions.values()[0];
+ sensor.shading_resolution = setting.register_dpihw;
+ sensor.pixel_count_ratio = setting.pixel_count_ratio;
+ sensor.shading_factor = setting.shading_factor;
+ s_sensors->push_back(sensor);
+ }
+ }
sensor = Genesys_Sensor();
- sensor.sensor_id = SensorId::CIS_CANON_LIDE_80;
- sensor.optical_res = 1200; // real hardware limit is 2400
- sensor.ccd_size_divisor = 2;
+ sensor.sensor_id = SensorId::CIS_CANON_LIDE_80; // gl841
+ sensor.full_resolution = 1200; // real hardware limit is 2400
+ sensor.register_dpihw = 1200;
sensor.black_pixels = 20;
sensor.dummy_pixel = 6;
- // tuned to give 3*8 multiple startx coordinate during shading calibration
- sensor.ccd_start_xoffset = 34; // 14=>3, 20=>2
- // 10400, too wide=>10288 in shading data 10240~
- // 10208 too short for shading, max shading data = 10240 pixels, endpix-startpix=10208
- sensor.sensor_pixels = 10240;
sensor.fau_gain_white_ref = 150;
sensor.gain_white_ref = 150;
// maps to 0x70-0x73 for GL841
sensor.exposure = { 0x1000, 0x1000, 0x0500 };
sensor.custom_regs = {
- { 0x08, 0x00 },
- { 0x09, 0x05 },
- { 0x0a, 0x07 },
- { 0x0b, 0x09 },
- { 0x16, 0x00 },
- { 0x17, 0x01 },
- { 0x18, 0x00 },
- { 0x19, 0x06 },
- { 0x1a, 0x00 },
- { 0x1b, 0x00 },
- { 0x1c, 0x00 },
- { 0x1d, 0x04 },
- { 0x52, 0x03 },
- { 0x53, 0x07 },
- { 0x54, 0x00 },
- { 0x55, 0x00 },
- { 0x56, 0x00 },
- { 0x57, 0x00 },
- { 0x58, 0x29 },
- { 0x59, 0x69 },
- { 0x5a, 0x55 },
- { 0x5b, 0x00 },
- { 0x5c, 0x00 },
- { 0x5d, 0x20 },
- { 0x5e, 0x41 },
+ { 0x16, 0x00 }, { 0x17, 0x01 }, { 0x18, 0x00 }, { 0x19, 0x06 },
+ { 0x1a, 0x00 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x04 },
+ { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 },
+ { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x29 }, { 0x59, 0x69 }, { 0x5a, 0x55 },
+ { 0x70, 0x00 }, { 0x71, 0x05 }, { 0x72, 0x07 }, { 0x73, 0x09 },
};
sensor.gamma = { 1.0f, 1.0f, 1.0f };
- sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_register_hwdpi_fun = default_get_logical_hwdpi;
- sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi;
- sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi;
- s_sensors->push_back(sensor);
+ {
+ struct CustomSensorSettings
+ {
+ ValueFilterAny<unsigned> resolutions;
+ unsigned optical_resolution;
+ unsigned register_dpiset;
+ unsigned shading_resolution;
+ unsigned shading_factor;
+ int output_pixel_offset;
+ };
+
+ CustomSensorSettings custom_settings[] = {
+ { { 75 }, 600, 150, 600, 8, 2 },
+ { { 100 }, 600, 200, 600, 6, 3 },
+ { { 150 }, 600, 300, 600, 4, 4 },
+ { { 200 }, 600, 400, 600, 3, 6 },
+ { { 300 }, 600, 600, 600, 2, 9 },
+ { { 600 }, 600, 1200, 600, 1, 17 },
+ { { 1200 }, 1200, 1200, 1200, 1, 35 },
+ };
+
+ for (const CustomSensorSettings& setting : custom_settings) {
+ sensor.resolutions = setting.resolutions;
+ sensor.optical_resolution = setting.optical_resolution;
+ sensor.register_dpiset = setting.register_dpiset;
+ sensor.shading_resolution = setting.shading_resolution;
+ sensor.shading_factor = setting.shading_factor;
+ sensor.output_pixel_offset = setting.output_pixel_offset;
+ s_sensors->push_back(sensor);
+ }
+ }
+}
+
+void verify_sensor_tables()
+{
+ std::map<SensorId, AsicType> sensor_to_asic;
+ for (const auto& device : *s_usb_devices) {
+ sensor_to_asic[device.model().sensor_id] = device.model().asic_type;
+ }
+ for (const auto& sensor : *s_sensors) {
+ if (sensor_to_asic.count(sensor.sensor_id) == 0) {
+ throw SaneException("Unknown asic for sensor");
+ }
+ auto asic_type = sensor_to_asic[sensor.sensor_id];
+
+ if (sensor.full_resolution == 0) {
+ throw SaneException("full_resolution is not defined");
+ }
+
+ if (sensor.register_dpiset == 0) {
+ throw SaneException("register_dpiset is not defined");
+ }
+
+ if (asic_type != AsicType::GL646) {
+ if (sensor.register_dpihw == 0) {
+ throw SaneException("register_dpihw is not defined");
+ }
+ if (sensor.shading_resolution == 0) {
+ throw SaneException("shading_resolution is not defined");
+ }
+ }
+
+ if (asic_type == AsicType::GL841) {
+ auto required_registers = {
+ 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
+ 0x70, 0x71, 0x72, 0x73,
+ };
+ for (auto address : required_registers) {
+ if (!sensor.custom_regs.has_reg(address)) {
+ throw SaneException("Required register is not present");
+ }
+ }
+ }
+
+ if (asic_type == AsicType::GL842) {
+ auto required_registers = {
+ 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1c, 0x1d,
+ 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d,
+ 0x7f
+ };
+ for (auto address : required_registers) {
+ if (!sensor.custom_regs.has_reg(address)) {
+ throw SaneException("Required register is not present");
+ }
+ }
+ }
+ }
}
+
} // namespace genesys
diff --git a/backend/genesys/test_scanner_interface.cpp b/backend/genesys/test_scanner_interface.cpp
index 12f726f..e8af494 100644
--- a/backend/genesys/test_scanner_interface.cpp
+++ b/backend/genesys/test_scanner_interface.cpp
@@ -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)
diff --git a/backend/genesys/test_scanner_interface.h b/backend/genesys/test_scanner_interface.h
index acf0f6d..fc8128c 100644
--- a/backend/genesys/test_scanner_interface.h
+++ b/backend/genesys/test_scanner_interface.h
@@ -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;
diff --git a/backend/genesys/test_settings.cpp b/backend/genesys/test_settings.cpp
index 425f09c..f328709 100644
--- a/backend/genesys/test_settings.cpp
+++ b/backend/genesys/test_settings.cpp
@@ -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;
diff --git a/backend/genesys/test_settings.h b/backend/genesys/test_settings.h
index 8ac03e0..38cc3b3 100644
--- a/backend/genesys/test_settings.h
+++ b/backend/genesys/test_settings.h
@@ -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();
diff --git a/backend/genesys/test_usb_device.cpp b/backend/genesys/test_usb_device.cpp
index de2399e..1612eae 100644
--- a/backend/genesys/test_usb_device.cpp
+++ b/backend/genesys/test_usb_device.cpp
@@ -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,
diff --git a/backend/genesys/test_usb_device.h b/backend/genesys/test_usb_device.h
index abbd78a..03b49cc 100644
--- a/backend/genesys/test_usb_device.h
+++ b/backend/genesys/test_usb_device.h
@@ -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
diff --git a/backend/genesys/usb_device.cpp b/backend/genesys/usb_device.cpp
index 2d02219..d6cbaed 100644
--- a/backend/genesys/usb_device.cpp
+++ b/backend/genesys/usb_device.cpp
@@ -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,
diff --git a/backend/genesys/usb_device.h b/backend/genesys/usb_device.h
index 265c57c..aa8b89a 100644
--- a/backend/genesys/usb_device.h
+++ b/backend/genesys/usb_device.h
@@ -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;
diff --git a/backend/genesys/utilities.h b/backend/genesys/utilities.h
index 1e268b5..fdab770 100644
--- a/backend/genesys/utilities.h
+++ b/backend/genesys/utilities.h
@@ -46,12 +46,81 @@
#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>
+inline T abs_diff(T a, T b)
+{
+ if (a < b) {
+ return b - a;
+ } else {
+ return a - b;
+ }
+}
+
+inline std::uint64_t align_multiple_floor(std::uint64_t x, std::uint64_t multiple)
+{
+ if (multiple == 0) {
+ return x;
+ }
+ return (x / multiple) * multiple;
+}
+
+inline std::uint64_t align_multiple_ceil(std::uint64_t x, std::uint64_t multiple)
+{
+ if (multiple == 0) {
+ return x;
+ }
+ return ((x + multiple - 1) / multiple) * multiple;
+}
+
+inline std::uint64_t multiply_by_depth_ceil(std::uint64_t pixels, std::uint64_t depth)
+{
+ if (depth == 1) {
+ return (pixels / 8) + ((pixels % 8) ? 1 : 0);
+ } else {
+ return pixels * (depth / 8);
+ }
+}
+
+template<class T>
+inline T clamp(const T& value, const T& lo, const T& hi)
+{
+ if (value < lo)
+ return lo;
+ if (value > hi)
+ return hi;
+ return value;
+}
+
template<class T>
void compute_array_percentile_approx(T* result, const T* data,
std::size_t line_count, std::size_t elements_per_line,
@@ -85,6 +154,75 @@ void compute_array_percentile_approx(T* result, const T* data,
}
}
+class Ratio
+{
+public:
+ Ratio() : multiplier_{1}, divisor_{1}
+ {
+ }
+
+ Ratio(unsigned multiplier, unsigned divisor) : multiplier_{multiplier}, divisor_{divisor}
+ {
+ }
+
+ unsigned multiplier() const { return multiplier_; }
+ unsigned divisor() const { return divisor_; }
+
+ unsigned apply(unsigned arg) const
+ {
+ return static_cast<std::uint64_t>(arg) * multiplier_ / divisor_;
+ }
+
+ int apply(int arg) const
+ {
+ return static_cast<std::int64_t>(arg) * multiplier_ / divisor_;
+ }
+
+ float apply(float arg) const
+ {
+ return arg * multiplier_ / divisor_;
+ }
+
+ unsigned apply_inverse(unsigned arg) const
+ {
+ return static_cast<std::uint64_t>(arg) * divisor_ / multiplier_;
+ }
+
+ int apply_inverse(int arg) const
+ {
+ return static_cast<std::int64_t>(arg) * divisor_ / multiplier_;
+ }
+
+ float apply_inverse(float arg) const
+ {
+ return arg * divisor_ / multiplier_;
+ }
+
+ bool operator==(const Ratio& other) const
+ {
+ return multiplier_ == other.multiplier_ && divisor_ == other.divisor_;
+ }
+private:
+ unsigned multiplier_;
+ unsigned divisor_;
+
+ template<class Stream>
+ friend void serialize(Stream& str, Ratio& x);
+};
+
+template<class Stream>
+void serialize(Stream& str, Ratio& x)
+{
+ serialize(str, x.multiplier_);
+ serialize(str, x.divisor_);
+}
+
+inline std::ostream& operator<<(std::ostream& out, const Ratio& ratio)
+{
+ out << ratio.multiplier() << "/" << ratio.divisor();
+ return out;
+}
+
template<class Char, class Traits>
class BasicStreamStateSaver
{
diff --git a/backend/genesys/value_filter.h b/backend/genesys/value_filter.h
new file mode 100644
index 0000000..ba55567
--- /dev/null
+++ b/backend/genesys/value_filter.h
@@ -0,0 +1,140 @@
+/* sane - Scanner Access Now Easy.
+
+ Copyright (C) 2020 Povilas Kanapickas <povilas@radix.lt>
+
+ This file is part of the SANE package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+*/
+
+#ifndef BACKEND_GENESYS_VALUE_FILTER_H
+#define BACKEND_GENESYS_VALUE_FILTER_H
+
+#include <algorithm>
+#include <initializer_list>
+#include <iostream>
+#include <vector>
+
+namespace genesys {
+
+struct AnyTag {};
+constexpr AnyTag VALUE_FILTER_ANY{};
+
+template<class T>
+class ValueFilterAny
+{
+public:
+ ValueFilterAny() : matches_any_{false} {}
+ ValueFilterAny(AnyTag) : matches_any_{true} {}
+ ValueFilterAny(std::initializer_list<T> values) :
+ matches_any_{false},
+ values_{values}
+ {}
+
+ bool matches(T value) const
+ {
+ if (matches_any_)
+ return true;
+ auto it = std::find(values_.begin(), values_.end(), value);
+ return it != values_.end();
+ }
+
+ bool operator==(const ValueFilterAny& other) const
+ {
+ return matches_any_ == other.matches_any_ && values_ == other.values_;
+ }
+
+ bool matches_any() const { return matches_any_; }
+ const std::vector<T>& values() const { return values_; }
+
+private:
+ bool matches_any_ = false;
+ std::vector<T> values_;
+
+ template<class Stream, class U>
+ friend void serialize(Stream& str, ValueFilterAny<U>& x);
+};
+
+template<class T>
+std::ostream& operator<<(std::ostream& out, const ValueFilterAny<T>& values)
+{
+ if (values.matches_any()) {
+ out << "ANY";
+ return out;
+ }
+ out << format_vector_indent_braced(4, "", values.values());
+ return out;
+}
+
+template<class Stream, class T>
+void serialize(Stream& str, ValueFilterAny<T>& x)
+{
+ serialize(str, x.matches_any_);
+ serialize_newline(str);
+ serialize(str, x.values_);
+}
+
+
+template<class T>
+class ValueFilter
+{
+public:
+ ValueFilter() = default;
+ ValueFilter(std::initializer_list<T> values) :
+ values_{values}
+ {}
+
+ bool matches(T value) const
+ {
+ auto it = std::find(values_.begin(), values_.end(), value);
+ return it != values_.end();
+ }
+
+ bool operator==(const ValueFilter& other) const
+ {
+ return values_ == other.values_;
+ }
+
+ const std::vector<T>& values() const { return values_; }
+
+private:
+ std::vector<T> values_;
+
+ template<class Stream, class U>
+ friend void serialize(Stream& str, ValueFilter<U>& x);
+};
+
+template<class T>
+std::ostream& operator<<(std::ostream& out, const ValueFilter<T>& values)
+{
+ if (values.values().empty()) {
+ out << "(none)";
+ return out;
+ }
+ out << format_vector_indent_braced(4, "", values.values());
+ return out;
+}
+
+template<class Stream, class T>
+void serialize(Stream& str, ValueFilter<T>& x)
+{
+ serialize_newline(str);
+ serialize(str, x.values_);
+}
+
+} // namespace genesys
+
+#endif // BACKEND_GENESYS_VALUE_FILTER_H
diff --git a/backend/gt68xx.c b/backend/gt68xx.c
index 00190fe..f657d42 100644
--- a/backend/gt68xx.c
+++ b/backend/gt68xx.c
@@ -2130,6 +2130,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len,
&& s->byte_count >= s->reader->params.pixel_xs)
{
DBG (4, "sane_read: nothing more to scan: EOF\n");
+ gt68xx_scanner_stop_scan(s);
return SANE_STATUS_EOF;
}
@@ -2343,8 +2344,10 @@ sane_cancel (SANE_Handle handle)
gt68xx_device_carriage_home (s->dev);
}
if (s->gamma_table)
- free (s->gamma_table);
- s->gamma_table = 0;
+ {
+ free (s->gamma_table);
+ s->gamma_table = 0;
+ }
}
else
{
diff --git a/backend/gt68xx.conf.in b/backend/gt68xx.conf.in
index e9a9706..af5ebe3 100644
--- a/backend/gt68xx.conf.in
+++ b/backend/gt68xx.conf.in
@@ -1,5 +1,5 @@
-# gt68xx.conf: Configuration file for GT68XX based scanners (@PACKAGEVERSION@)
+# gt68xx.conf: Configuration file for GT68XX based scanners
# Read man sane-gt68xx for documentation
# Put the firmware file into "@DATADIR@/sane/gt68xx/".
diff --git a/backend/gt68xx_high.c b/backend/gt68xx_high.c
index 782b4f3..563323c 100644
--- a/backend/gt68xx_high.c
+++ b/backend/gt68xx_high.c
@@ -97,7 +97,7 @@ gt68xx_calibrator_new (SANE_Int width,
cal->white_line = (double *) malloc (width * sizeof (double));
cal->black_line = (double *) malloc (width * sizeof (double));
- if (!cal->k_white || !cal->k_black | !cal->white_line || !cal->black_line)
+ if (!cal->k_white || !cal->k_black || !cal->white_line || !cal->black_line)
{
DBG (5, "gt68xx_calibrator_new: no memory for calibration data\n");
gt68xx_calibrator_free (cal);
diff --git a/backend/gt68xx_mid.c b/backend/gt68xx_mid.c
index 0d5cbe4..1d6a5c6 100644
--- a/backend/gt68xx_mid.c
+++ b/backend/gt68xx_mid.c
@@ -1006,6 +1006,7 @@ gt68xx_line_reader_new (GT68xx_Device * dev,
DBG (3, "gt68xx_line_reader_new: cannot allocate line buffers: %s\n",
sane_strstatus (status));
free (reader);
+ reader = NULL;
return status;
}
@@ -1105,6 +1106,7 @@ gt68xx_line_reader_new (GT68xx_Device * dev,
reader->params.depth);
gt68xx_line_reader_free_delays (reader);
free (reader);
+ reader = NULL;
return SANE_STATUS_UNSUPPORTED;
}
@@ -1119,6 +1121,7 @@ gt68xx_line_reader_new (GT68xx_Device * dev,
DBG (3, "gt68xx_line_reader_new: cannot allocate pixel buffer\n");
gt68xx_line_reader_free_delays (reader);
free (reader);
+ reader = NULL;
return SANE_STATUS_NO_MEM;
}
@@ -1135,6 +1138,7 @@ gt68xx_line_reader_new (GT68xx_Device * dev,
free (reader->pixel_buffer);
gt68xx_line_reader_free_delays (reader);
free (reader);
+ reader = NULL;
return status;
}
@@ -1150,6 +1154,13 @@ gt68xx_line_reader_free (GT68xx_Line_Reader * reader)
DBG (6, "gt68xx_line_reader_free: enter\n");
+ if (reader == NULL)
+ {
+ DBG (3, "gt68xx_line_reader_free: already freed\n");
+ DBG (6, "gt68xx_line_reader_free: leave\n");
+ return SANE_STATUS_INVAL;
+ }
+
gt68xx_line_reader_free_delays (reader);
if (reader->pixel_buffer)
@@ -1167,6 +1178,7 @@ gt68xx_line_reader_free (GT68xx_Line_Reader * reader)
}
free (reader);
+ reader = NULL;
DBG (6, "gt68xx_line_reader_free: leave\n");
return status;
diff --git a/backend/hp5400.h b/backend/hp5400.h
index b0efb4f..78244e0 100644
--- a/backend/hp5400.h
+++ b/backend/hp5400.h
@@ -1,4 +1,5 @@
/* sane - Scanner Access Now Easy.
+ Copyright (C) 20020 Ralph Little <skelband@gmail.com>
Copyright (C) 2003 Martijn van Oosterhout <kleptog@svana.org>
Copyright (C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
@@ -138,6 +139,16 @@ typedef struct
}
TScanParams;
+/*
+ * Panel settings. We can read and set these.
+ *
+ */
+typedef struct
+{
+ SANE_Word copycount; // 0..99 LCD display value
+ SANE_Word bwcolour; // 1=Colour or 2=Black/White from scan type LEDs
+}
+TPanelInfo;
#endif /* NO _HP5400_H_ */
diff --git a/backend/hp5400_internal.c b/backend/hp5400_internal.c
index 34bf55d..1d81358 100644
--- a/backend/hp5400_internal.c
+++ b/backend/hp5400_internal.c
@@ -1,4 +1,5 @@
/* sane - Scanner Access Now Easy.
+ Copyright (C) 2020 Ralph Little <skelband@gmail.com>
Copyright (C) 2003 Martijn van Oosterhout <kleptog@svana.org>
Copyright (C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
Copyright (c) 2003 Henning Meier-Geinitz, <henning@meier-geinitz.de>
@@ -149,11 +150,138 @@ SetLamp (THWParams * pHWParams, int fLampOn)
if (fLampOn)
{
if (WriteByte (pHWParams->iXferHandle, 0x0000, 0x01) == 0)
- return 0;
+ return 0;
}
return -1;
}
+
+HP5400_SANE_STATIC
+int
+GetSensors(THWParams * pHWParams, uint16_t *sensorMap)
+{
+ /*
+ * Read until we get 0.
+ * Max 10 iterations for safety.
+ *
+ */
+ *sensorMap = 0;
+ uint16_t thisSensorMap = 0;
+ size_t iterCount = 10;
+ do
+ {
+ if (hp5400_command_read
+ (pHWParams->iXferHandle, CMD_GETSENSORS, sizeof (uint16_t), &thisSensorMap) < 0)
+ {
+ HP5400_DBG (DBG_MSG, "failed to read sensors\n");
+ return -1;
+ }
+ *sensorMap |= thisSensorMap;
+ } while (iterCount-- && (thisSensorMap > 0));
+
+ return 0;
+}
+
+HP5400_SANE_STATIC
+int
+GetPanelInfo (THWParams * pHWParams, TPanelInfo *panelInfo)
+{
+ struct PanelInfo info;
+ if (hp5400_command_read (pHWParams->iXferHandle, CMD_READPANEL,
+ sizeof(info), &info) < 0)
+ {
+ HP5400_DBG (DBG_MSG, "failed to read panel info\n");
+ return -1;
+ }
+
+ panelInfo->copycount = (SANE_Word)info.copycount;
+ panelInfo->bwcolour = (SANE_Word)info.bwcolour;
+
+ return 0;
+}
+
+HP5400_SANE_STATIC
+int
+SetCopyCount(THWParams * pHWParams, SANE_Word copyCount)
+{
+
+ /*
+ * I don't know what most of these things are but it is
+ * necessary to send something sane otherwise we get an error from the scanner.
+ * I got these settings from a USB trace.
+ * Hopefully, we will learn what it is all about at some point
+ * and hopefully it doesn't screw with other settings.
+ *
+ */
+ uint8_t packetImage[] = {0x02, 0x06, 0x32, 0x01,
+ 0xf2, 0x40, 0x16, 0x01,
+ 0x7b, 0x41, 0x16, 0x01,
+ 0xdc, 0x06, 0x32, 0x01,
+ 0xd7, 0x5b, 0x16, 0x01,
+ 0xac, 0x06, 0x32, 0x01,
+ 0xf8, 0xd7, 0x18, 0x01,
+ 0xd8, 0x06, 0x32, 0x01,
+ 0x2c, 0xf3, 0x12, 0x00,
+ 0x70, 0x8d, 0x18, 0x01,
+ 0x7b, 0x00, 0x00, 0x00};
+
+ struct PanelInfo workingInfo;
+ (void)memcpy(&workingInfo, packetImage, sizeof(workingInfo));
+
+ workingInfo.copycount = (uint8_t)copyCount;
+
+ if (hp5400_command_write (pHWParams->iXferHandle, CMD_WRITEPANEL,
+ sizeof(workingInfo), &workingInfo) < 0)
+ {
+ HP5400_DBG (DBG_MSG, "failed to write panel info\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+HP5400_SANE_STATIC
+int
+SetColourBW(THWParams * pHWParams, SANE_Word colourBW)
+{
+
+ /*
+ * I don't know what most of these things are but it is
+ * necessary to send something sane otherwise we get an error from the scanner.
+ * I got these settings from a USB trace.
+ * Hopefully, we will learn what it is all about at some point
+ * and hopefully it doesn't screw with other settings.
+ *
+ */
+ uint8_t packetImage[] = {0x03, 0x06, 0x32, 0x01,
+ 0xf2, 0x40, 0x16, 0x01,
+ 0x7b, 0x41, 0x16, 0x01,
+ 0xdc, 0x06, 0x32, 0x01,
+ 0xd7, 0x5b, 0x16, 0x01,
+ 0xac, 0x06, 0x32, 0x01,
+ 0xf8, 0xd7, 0x18, 0x01,
+ 0xd8, 0x06, 0x32, 0x01,
+ 0x68, 0xf5, 0x12, 0x00,
+ 0x70, 0x8d, 0x18, 0x01,
+ 0x7b, 0x00, 0x00, 0x00};
+
+ struct PanelInfo workingInfo;
+ (void)memcpy(&workingInfo, packetImage, sizeof(workingInfo));
+
+ workingInfo.bwcolour = (uint8_t)colourBW;
+
+ if (hp5400_command_write (pHWParams->iXferHandle, CMD_WRITEPANEL,
+ sizeof(workingInfo), &workingInfo) < 0)
+ {
+ HP5400_DBG (DBG_MSG, "failed to write panel info\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
HP5400_SANE_STATIC
int
WarmupLamp (int iHandle)
diff --git a/backend/hp5400_internal.h b/backend/hp5400_internal.h
index 981ce0b..aa40da0 100644
--- a/backend/hp5400_internal.h
+++ b/backend/hp5400_internal.h
@@ -2,6 +2,7 @@
#define _HP5400_INTERNAL_H_
/* sane - Scanner Access Now Easy.
+ Copyright (C) 2020 Ralph Little <skelband@gmail.com>
(C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
(c) 2003 Martijn van Oosterhout, kleptog@svana.org
(c) 2002 Bertrik Sikken, bertrik@zonnet.nl
@@ -73,6 +74,9 @@
#define CMD_SCANREQUEST 0x2505 /* This is for previews */
#define CMD_SCANREQUEST2 0x2500 /* This is for real scans */
#define CMD_SCANRESPONSE 0x3400
+#define CMD_GETSENSORS 0x2000
+#define CMD_READPANEL 0x2100 // Reads info from the scanner. BW/Col + Copy Count. Others, not sure.
+#define CMD_WRITEPANEL 0x2200 // Ditto for setting.
/* Testing stuff to make it work */
#define CMD_SETDPI 0x1500 /* ??? */
@@ -130,11 +134,40 @@ PACKED;
struct ScanResponse
{
- uint16_t x1; /* Usually 0x0000 or 0x4000 */
- uint32_t transfersize; /* Number of bytes to be transferred */
- uint32_t xsize; /* Shape of returned bitmap */
- uint16_t ysize; /* Why does the X get more bytes? */
- uint16_t pad[2]; /* Zero padding to 16 bytes??? */
+ uint16_t x1; /* Usually 0x0000 or 0x4000 */
+ uint32_t transfersize; /* Number of bytes to be transferred */
+ uint32_t xsize; /* Shape of returned bitmap */
+ uint16_t ysize; /* Why does the X get more bytes? */
+ uint16_t pad[2]; /* Zero padding to 16 bytes??? */
+}
+PACKED;
+
+/*
+ * Note: this is the structure of the response we get from CMD_READPANEL.
+ * We only know about two items for the moment. The rest will be ignored
+ * until we understand it better.
+ *
+ * 44 bytes in total.
+ *
+ * Since we don't know what the other things mean, I will assume that they
+ * mean the same things for Get and SET. For SET, we will have to GET, change
+ * what we wish change and SET it back otherwise goodness knows what evil
+ * we will unleash.
+ *
+ * Note that for setting, different values in the buffer seem to apply betwen the copy count
+ * and the colour/BW switch setting. I don't know what that means at the moment.
+ *
+ * I'm calling it PanelInfo because I can't think of anything better.
+ * That may change as the other values are revealed.
+ *
+ */
+struct PanelInfo
+{
+ uint32_t unknown1[10];
+ uint8_t unknown2;
+ uint8_t copycount; // 0..99 from the LCD display.
+ uint8_t bwcolour; // 1 or 2 from the Colour/BW leds.
+ uint8_t unknown3;
}
PACKED;
@@ -158,6 +191,22 @@ SetLamp (THWParams * pHWParams, int fLampOn);
HP5400_SANE_STATIC
int
+GetSensors (THWParams * pHWParams, uint16_t *sensorMap);
+
+HP5400_SANE_STATIC
+int
+GetPanelInfo (THWParams * pHWParams, TPanelInfo *panelInfo);
+
+HP5400_SANE_STATIC
+int
+SetCopyCount(THWParams * pHWParams, SANE_Word copyCount);
+
+HP5400_SANE_STATIC
+int
+SetColourBW(THWParams * pHWParams, SANE_Word colourBW);
+
+HP5400_SANE_STATIC
+int
WarmupLamp (int iHandle);
HP5400_SANE_STATIC
diff --git a/backend/hp5400_sane.c b/backend/hp5400_sane.c
index e5fdf43..b6fa6da 100644
--- a/backend/hp5400_sane.c
+++ b/backend/hp5400_sane.c
@@ -1,4 +1,5 @@
/* sane - Scanner Access Now Easy.
+ Copyright (C) 2020 Ralph Little <skelband@gmail.com>
Copyright (C) 2003 Martijn van Oosterhout <kleptog@svana.org>
Copyright (C) 2003 Thomas Soumarmon <thomas.soumarmon@cogitae.net>
@@ -71,28 +72,6 @@
#include "hp5400.h"
-/* includes for data transfer methods */
-#include "hp5400.h"
-
-#ifdef STANDALONE
-#include "hp5400_scanner.h"
-#endif
-
-#if defined(LINUX_USB_SUPPORT)
- #include "hp5400_linux.c"
-#endif
-#if defined(USCANNER_SUPPORT)
- #include "hp5400_uscanner.c"
-#endif
-#if defined(LIBUSB_SUPPORT)
- #include "hp5400_libusb.c"
-#endif
-#if defined(LIBIEEE1284_SUPPORT)
- #include "hp5400_ieee1284.c"
-#endif
-
-
-
/* other definitions */
#ifndef min
#define min(A,B) (((A)<(B)) ? (A) : (B))
@@ -115,30 +94,91 @@ typedef enum
{
optCount = 0,
+ optDPI,
+
optGroupGeometry,
optTLX, optTLY, optBRX, optBRY,
- optDPI,
- optGroupImage,
+ optGroupEnhancement,
optGammaTableRed, /* Gamma Tables */
optGammaTableGreen,
optGammaTableBlue,
- optLast, /* Disable the offset code */
+ optGroupSensors,
- optGroupMisc,
- optOffsetX, optOffsetY
+ optSensorScanTo,
+ optSensorWeb,
+ optSensorReprint,
+ optSensorEmail,
+ optSensorCopy,
+ optSensorMoreOptions,
+ optSensorCancel,
+ optSensorPowerSave,
+ optSensorCopiesUp,
+ optSensorCopiesDown,
+ optSensorColourBW,
+ optSensorColourBWState,
+ optSensorCopyCount,
-/* put temporarily disabled options here after optLast */
-/*
- optLamp,
-*/
+ // Unsupported as yet.
+ //optGroupMisc,
+ //optLamp,
+ //optCalibrate,
+ optLast, /* Disable the offset code */
}
EOptionIndex;
+/*
+ * Array mapping (optSensor* - optGroupSensors - 1) to the bit mask of the
+ * corresponding sensor bit that we get from the scanner.
+ * All sensor bits are reported as a complete 16-bit word with individual bits set
+ * to indicate that the sensor has been activated.
+ * They seem to be latched so that they are picked up on next query and a number
+ * of bits can be set in any one query.
+ *
+ */
+
+#define SENSOR_BIT_SCAN 0x0400
+#define SENSOR_BIT_WEB 0x0200
+#define SENSOR_BIT_REPRINT 0x0002
+#define SENSOR_BIT_EMAIL 0x0080
+#define SENSOR_BIT_COPY 0x0040
+#define SENSOR_BIT_MOREOPTIONS 0x0004
+#define SENSOR_BIT_CANCEL 0x0100
+#define SENSOR_BIT_POWERSAVE 0x2000
+#define SENSOR_BIT_COPIESUP 0x0008
+#define SENSOR_BIT_COPIESDOWN 0x0020
+#define SENSOR_BIT_COLOURBW 0x0010
+
+
+uint16_t sensorMaskMap[] =
+{
+ SENSOR_BIT_SCAN,
+ SENSOR_BIT_WEB,
+ SENSOR_BIT_REPRINT,
+ SENSOR_BIT_EMAIL,
+ SENSOR_BIT_COPY,
+ SENSOR_BIT_MOREOPTIONS,
+ SENSOR_BIT_CANCEL,
+
+ // Special buttons.
+ // These affect local machine settings, but we can still detect them being pressed.
+ SENSOR_BIT_POWERSAVE,
+ SENSOR_BIT_COPIESUP,
+ SENSOR_BIT_COPIESDOWN,
+ SENSOR_BIT_COLOURBW,
+
+ // Extra entries to make the array up to the 16 possible bits.
+ 0x0000, // Unused
+ 0x0000, // Unused
+ 0x0000, // Unused
+ 0x0000, // Unused
+ 0x0000 // Unused
+};
+
typedef union
{
SANE_Word w;
@@ -165,6 +205,8 @@ typedef struct
int fScanning; /* TRUE if actively scanning */
int fCanceled;
+
+ uint16_t sensorMap; /* Contains the current unreported sensor bits. */
}
TScanner;
@@ -191,18 +233,19 @@ static const SANE_Device **_pSaneDevList = 0;
/* option constraints */
static const SANE_Range rangeGammaTable = {0, 65535, 1};
+static const SANE_Range rangeCopyCountTable = {0, 99, 1};
+static SANE_String_Const modeSwitchList[] = {
+ SANE_VALUE_SCAN_MODE_COLOR,
+ SANE_VALUE_SCAN_MODE_GRAY,
+ NULL
+};
#ifdef SUPPORT_2400_DPI
static const SANE_Int setResolutions[] = {6, 75, 150, 300, 600, 1200, 2400};
#else
static const SANE_Int setResolutions[] = {5, 75, 150, 300, 600, 1200};
#endif
-static const SANE_Range rangeXmm = {0, 220, 1};
-static const SANE_Range rangeYmm = {0, 300, 1};
-static const SANE_Range rangeXoffset = {0, 20, 1};
-static const SANE_Range rangeYoffset = {0, 70, 1};
-static const SANE_Int offsetX = 5;
-static const SANE_Int offsetY = 52;
-
+static const SANE_Range rangeXmm = {0, 216, 1};
+static const SANE_Range rangeYmm = {0, 297, 1};
static void _InitOptions(TScanner *s)
{
@@ -248,8 +291,22 @@ static void _InitOptions(TScanner *s)
pVal->w = (SANE_Word)optLast;
break;
+ case optDPI:
+ pDesc->name = SANE_NAME_SCAN_RESOLUTION;
+ pDesc->title = SANE_TITLE_SCAN_RESOLUTION;
+ pDesc->desc = SANE_DESC_SCAN_RESOLUTION;
+ pDesc->unit = SANE_UNIT_DPI;
+ pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
+ pDesc->constraint.word_list = setResolutions;
+ pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
+ pVal->w = setResolutions[1];
+ break;
+
+ //---------------------------------
case optGroupGeometry:
- pDesc->title = "Geometry";
+ pDesc->name = SANE_NAME_GEOMETRY;
+ pDesc->title = SANE_TITLE_GEOMETRY;
+ pDesc->desc = SANE_DESC_GEOMETRY;
pDesc->type = SANE_TYPE_GROUP;
pDesc->size = 0;
break;
@@ -262,7 +319,7 @@ static void _InitOptions(TScanner *s)
pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
pDesc->constraint.range = &rangeXmm;
pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
- pVal->w = rangeXmm.min + offsetX;
+ pVal->w = rangeXmm.min;
break;
case optTLY:
@@ -273,7 +330,7 @@ static void _InitOptions(TScanner *s)
pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
pDesc->constraint.range = &rangeYmm;
pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
- pVal->w = rangeYmm.min + offsetY;
+ pVal->w = rangeYmm.min;
break;
case optBRX:
@@ -284,7 +341,7 @@ static void _InitOptions(TScanner *s)
pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
pDesc->constraint.range = &rangeXmm;
pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
- pVal->w = rangeXmm.max + offsetX;
+ pVal->w = rangeXmm.max;
break;
case optBRY:
@@ -295,22 +352,14 @@ static void _InitOptions(TScanner *s)
pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
pDesc->constraint.range = &rangeYmm;
pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
- pVal->w = rangeYmm.max + offsetY;
- break;
-
- case optDPI:
- pDesc->name = SANE_NAME_SCAN_RESOLUTION;
- pDesc->title = SANE_TITLE_SCAN_RESOLUTION;
- pDesc->desc = SANE_DESC_SCAN_RESOLUTION;
- pDesc->unit = SANE_UNIT_DPI;
- pDesc->constraint_type = SANE_CONSTRAINT_WORD_LIST;
- pDesc->constraint.word_list = setResolutions;
- pDesc->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
- pVal->w = setResolutions[1];
+ pVal->w = rangeYmm.max;
break;
- case optGroupImage:
- pDesc->title = SANE_I18N("Image");
+ //---------------------------------
+ case optGroupEnhancement:
+ pDesc->name = SANE_NAME_ENHANCEMENT;
+ pDesc->title = SANE_TITLE_ENHANCEMENT;
+ pDesc->desc = SANE_DESC_ENHANCEMENT;
pDesc->type = SANE_TYPE_GROUP;
pDesc->size = 0;
break;
@@ -348,34 +397,130 @@ static void _InitOptions(TScanner *s)
pVal->wa = s->aGammaTableB;
break;
- case optGroupMisc:
- pDesc->title = SANE_I18N("Miscellaneous");
+ //---------------------------------
+ case optGroupSensors:
+ pDesc->name = SANE_NAME_SENSORS;
+ pDesc->title = SANE_TITLE_SENSORS;
pDesc->type = SANE_TYPE_GROUP;
+ pDesc->desc = SANE_DESC_SENSORS;
pDesc->size = 0;
break;
- case optOffsetX:
- pDesc->title = SANE_I18N("offset X");
- pDesc->desc = SANE_I18N("Hardware internal X position of the scanning area.");
- pDesc->unit = SANE_UNIT_MM;
- pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
- pDesc->constraint.range = &rangeXoffset;
- pDesc->cap = SANE_CAP_SOFT_SELECT;
- pVal->w = offsetX;
+ case optSensorScanTo:
+ pDesc->name = SANE_NAME_SCAN;
+ pDesc->title = SANE_TITLE_SCAN;
+ pDesc->desc = SANE_DESC_SCAN;
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
- case optOffsetY:
- pDesc->title = SANE_I18N("offset Y");
- pDesc->desc = SANE_I18N("Hardware internal Y position of the scanning area.");
- pDesc->unit = SANE_UNIT_MM;
- pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
- pDesc->constraint.range = &rangeYoffset;
- pDesc->cap = SANE_CAP_SOFT_SELECT;
- pVal->w = offsetY;
+ case optSensorWeb:
+ pDesc->name = SANE_I18N("web");
+ pDesc->title = SANE_I18N("Share-To-Web button");
+ pDesc->desc = SANE_I18N("Scan an image and send it on the web");
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
+ break;
+
+ case optSensorReprint:
+ pDesc->name = SANE_I18N("reprint");
+ pDesc->title = SANE_I18N("Reprint Photos button");
+ pDesc->desc = SANE_I18N("Button for reprinting photos");
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
+ break;
+
+ case optSensorEmail:
+ pDesc->name = SANE_NAME_EMAIL;
+ pDesc->title = SANE_TITLE_EMAIL;
+ pDesc->desc = SANE_DESC_EMAIL;
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
+ break;
+
+ case optSensorCopy:
+ pDesc->name = SANE_NAME_COPY;
+ pDesc->title = SANE_TITLE_COPY;
+ pDesc->desc = SANE_DESC_COPY;
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
+ break;
+
+ case optSensorMoreOptions:
+ pDesc->name = SANE_I18N("more-options");
+ pDesc->title = SANE_I18N("More Options button");
+ pDesc->desc = SANE_I18N("Button for additional options/configuration");
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
+ break;
+
+ case optSensorCancel:
+ pDesc->name = SANE_NAME_CANCEL;
+ pDesc->title = SANE_TITLE_CANCEL;
+ pDesc->desc = SANE_DESC_CANCEL;
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
+ break;
+
+ case optSensorPowerSave:
+ pDesc->name = SANE_I18N("power-save");
+ pDesc->title = SANE_I18N("Power Save button");
+ pDesc->desc = SANE_I18N("Puts the scanner in an energy-conservation mode");
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
+ break;
+
+ case optSensorCopiesUp:
+ pDesc->name = SANE_I18N("copies-up");
+ pDesc->title = SANE_I18N("Increase Copies button");
+ pDesc->desc = SANE_I18N("Increase the number of copies");
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
+ break;
+
+ case optSensorCopiesDown:
+ pDesc->name = SANE_I18N("copies-down");
+ pDesc->title = SANE_I18N("Decrease Copies button");
+ pDesc->desc = SANE_I18N("Decrease the number of copies");
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
break;
+ case optSensorColourBW:
+ pDesc->name = SANE_I18N("color-bw");
+ pDesc->title = SANE_I18N("Select color/BW button");
+ pDesc->desc = SANE_I18N("Alternates between color and black/white scanning");
+ pDesc->type = SANE_TYPE_BOOL;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
+ break;
+
+ case optSensorColourBWState:
+ pDesc->name = SANE_I18N("color-bw-state");
+ pDesc->title = SANE_I18N("Read color/BW button state");
+ pDesc->desc = SANE_I18N("Reads state of BW/colour panel setting");
+ pDesc->type = SANE_TYPE_STRING;
+ pDesc->constraint_type = SANE_CONSTRAINT_STRING_LIST;
+ pDesc->constraint.string_list = modeSwitchList;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED;
+ break;
+
+ case optSensorCopyCount:
+ pDesc->name = SANE_I18N("copies-count");
+ pDesc->title = SANE_I18N("Read copy count value");
+ pDesc->desc = SANE_I18N("Reads state of copy count panel setting");
+ pDesc->type = SANE_TYPE_INT;
+ pDesc->constraint_type = SANE_CONSTRAINT_RANGE;
+ pDesc->constraint.range = &rangeCopyCountTable;
+ pDesc->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED;
+ break;
#if 0
+ case optGroupMisc:
+ pDesc->title = SANE_I18N("Miscellaneous");
+ pDesc->type = SANE_TYPE_GROUP;
+ pDesc->size = 0;
+ break;
+
case optLamp:
pDesc->name = "lamp";
pDesc->title = SANE_I18N("Lamp status");
@@ -385,8 +530,7 @@ static void _InitOptions(TScanner *s)
/* switch the lamp on when starting for first the time */
pVal->w = SANE_TRUE;
break;
-#endif
-#if 0
+
case optCalibrate:
pDesc->name = "calibrate";
pDesc->title = SANE_I18N("Calibrate");
@@ -467,7 +611,7 @@ sane_init (SANE_Int * piVersion, SANE_Auth_Callback pfnAuth)
SANE_String_Const proper_str;
int nline = 0;
- /* prevent compiler from complaing about unused parameters */
+ /* prevent compiler from complaining about unused parameters */
pfnAuth = pfnAuth;
strcpy(usb_devfile, "/dev/usb/scanner0");
@@ -531,7 +675,6 @@ sane_init (SANE_Int * piVersion, SANE_Auth_Callback pfnAuth)
*piVersion = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, BUILD);
}
-
return SANE_STATUS_GOOD;
}
@@ -694,7 +837,7 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
/* Get options of type SANE_Word */
case optBRX:
case optTLX:
- *(SANE_Word *) pVal = s->aValues[n].w; /* Not needed anymore - s->aValues[optOffsetX].w; */
+ *(SANE_Word *) pVal = s->aValues[n].w;
HP5400_DBG (DBG_MSG,
"sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n,
*(SANE_Word *) pVal);
@@ -702,14 +845,12 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
case optBRY:
case optTLY:
- *(SANE_Word *) pVal = s->aValues[n].w; /* Not needed anymore - - s->aValues[optOffsetY].w; */
+ *(SANE_Word *) pVal = s->aValues[n].w;
HP5400_DBG (DBG_MSG,
"sane_control_option: SANE_ACTION_GET_VALUE %d = %d\n", n,
*(SANE_Word *) pVal);
break;
- case optOffsetX:
- case optOffsetY:
case optCount:
case optDPI:
HP5400_DBG (DBG_MSG,
@@ -726,14 +867,94 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
memcpy (pVal, s->aValues[n].wa, s->aOptions[n].size);
break;
+ case optSensorScanTo:
+ case optSensorWeb:
+ case optSensorReprint:
+ case optSensorEmail:
+ case optSensorCopy:
+ case optSensorMoreOptions:
+ case optSensorCancel:
+ case optSensorPowerSave:
+ case optSensorCopiesUp:
+ case optSensorCopiesDown:
+ case optSensorColourBW:
+ {
+ HP5400_DBG (DBG_MSG, "Reading sensor state\n");
+
+ uint16_t sensorMap;
+ if (GetSensors(&s->HWParams, &sensorMap) != 0)
+ {
+ HP5400_DBG (DBG_ERR,
+ "sane_control_option: SANE_ACTION_SET_VALUE could not retrieve sensors\n");
+ return SANE_STATUS_IO_ERROR;
+
+ }
+
+ HP5400_DBG (DBG_MSG, "Sensor state=%x\n", sensorMap);
+
+ // Add read flags to what we already have so that we can report them when requested.
+ s->sensorMap |= sensorMap;
+
+ // Look up the mask based on the option number.
+ uint16_t mask = sensorMaskMap[n - optGroupSensors - 1];
+ *(SANE_Word *) pVal = (s->sensorMap & mask)? 1:0;
+ s->sensorMap &= ~mask;
+ break;
+ }
+
+ case optSensorCopyCount:
+ {
+ HP5400_DBG (DBG_MSG, "Reading copy count\n");
+
+ TPanelInfo panelInfo;
+ if (GetPanelInfo(&s->HWParams, &panelInfo) != 0)
+ {
+ HP5400_DBG (DBG_ERR,
+ "sane_control_option: SANE_ACTION_SET_VALUE could not retrieve panel info\n");
+ return SANE_STATUS_IO_ERROR;
+
+ }
+
+ HP5400_DBG (DBG_MSG, "Copy count setting=%u\n", panelInfo.copycount);
+ *(SANE_Word *) pVal = panelInfo.copycount;
+ break;
+ }
+
+ case optSensorColourBWState:
+ {
+ HP5400_DBG (DBG_MSG, "Reading BW/Colour setting\n");
+
+ TPanelInfo panelInfo;
+ if (GetPanelInfo(&s->HWParams, &panelInfo) != 0)
+ {
+ HP5400_DBG (DBG_ERR,
+ "sane_control_option: SANE_ACTION_SET_VALUE could not retrieve panel info\n");
+ return SANE_STATUS_IO_ERROR;
+
+ }
+
+ HP5400_DBG (DBG_MSG, "BW/Colour setting=%u\n", panelInfo.bwcolour);
+
+ // Just for safety:
+ if (panelInfo.bwcolour < 1)
+ {
+ panelInfo.bwcolour = 1;
+ }
+ else if (panelInfo.bwcolour > 2)
+ {
+ panelInfo.bwcolour = 2;
+ }
+ (void)strcpy((SANE_String)pVal, modeSwitchList[panelInfo.bwcolour - 1]);
+ break;
+ }
+
#if 0
/* Get options of type SANE_Bool */
case optLamp:
GetLamp (&s->HWParams, &fLampIsOn);
*(SANE_Bool *) pVal = fLampIsOn;
break;
-#endif
-#if 0
+
case optCalibrate:
/* although this option has nothing to read,
it's added here to avoid a warning when running scanimage --help */
@@ -761,26 +982,70 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
case optBRX:
case optTLX:
- info |= SANE_INFO_RELOAD_PARAMS;
- s->ScanParams.iLines = 0; /* Forget actual image settings */
- s->aValues[n].w = *(SANE_Word *) pVal; /* Not needed anymore - + s->aValues[optOffsetX].w; */
- break;
-
- case optBRY:
- case optTLY:
- info |= SANE_INFO_RELOAD_PARAMS;
- s->ScanParams.iLines = 0; /* Forget actual image settings */
- s->aValues[n].w = *(SANE_Word *) pVal; /* Not needed anymore - + s->aValues[optOffsetY].w; */
- break;
- case optDPI:
- info |= SANE_INFO_RELOAD_PARAMS;
- s->ScanParams.iLines = 0; /* Forget actual image settings */
-#ifdef SUPPORT_2400_DPI
- (s->aValues[n].w) = *(SANE_Word *) pVal;
-#else
- (s->aValues[n].w) = min (1200, *(SANE_Word *) pVal);
-#endif
- break;
+ {
+ // Check against legal values.
+ SANE_Word value = *(SANE_Word *) pVal;
+ if ((value < s->aOptions[n].constraint.range->min) ||
+ (value > s->aOptions[n].constraint.range->max))
+ {
+ HP5400_DBG (DBG_ERR,
+ "sane_control_option: SANE_ACTION_SET_VALUE out of range X value\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ info |= SANE_INFO_RELOAD_PARAMS;
+ s->ScanParams.iLines = 0; /* Forget actual image settings */
+ s->aValues[n].w = value;
+ break;
+ }
+
+ case optBRY:
+ case optTLY:
+ {
+ // Check against legal values.
+ SANE_Word value = *(SANE_Word *) pVal;
+ if ((value < s->aOptions[n].constraint.range->min) ||
+ (value > s->aOptions[n].constraint.range->max))
+ {
+ HP5400_DBG (DBG_ERR,
+ "sane_control_option: SANE_ACTION_SET_VALUE out of range Y value\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ info |= SANE_INFO_RELOAD_PARAMS;
+ s->ScanParams.iLines = 0; /* Forget actual image settings */
+ s->aValues[n].w = value;
+ break;
+ }
+
+ case optDPI:
+ {
+ // Check against legal values.
+ SANE_Word dpiValue = *(SANE_Word *) pVal;
+
+ // First check too large.
+ SANE_Word maxRes = setResolutions[setResolutions[0]];
+ if (dpiValue > maxRes)
+ {
+ dpiValue = maxRes;
+ }
+ else // Check smaller values: if not exact match, pick next higher available.
+ {
+ for (SANE_Int resIdx = 1; resIdx <= setResolutions[0]; resIdx++)
+ {
+ if (dpiValue <= setResolutions[resIdx])
+ {
+ dpiValue = setResolutions[resIdx];
+ break;
+ }
+ }
+ }
+
+ info |= SANE_INFO_RELOAD_PARAMS;
+ s->ScanParams.iLines = 0; /* Forget actual image settings */
+ (s->aValues[n].w) = dpiValue;
+ break;
+ }
case optGammaTableRed:
case optGammaTableGreen:
@@ -788,6 +1053,70 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action Action,
HP5400_DBG (DBG_MSG, "Writing gamma table\n");
memcpy (s->aValues[n].wa, pVal, s->aOptions[n].size);
break;
+
+ case optSensorColourBWState:
+ {
+ SANE_String bwColour = (SANE_String)pVal;
+ SANE_Word bwColourValue;
+
+ if (strcmp(bwColour, SANE_VALUE_SCAN_MODE_COLOR) == 0)
+ {
+ bwColourValue = 1;
+ }
+ else if (strcmp(bwColour, SANE_VALUE_SCAN_MODE_GRAY) == 0)
+ {
+ bwColourValue = 2;
+ }
+ else
+ {
+ HP5400_DBG (DBG_ERR,
+ "sane_control_option: SANE_ACTION_SET_VALUE invalid colour/bw mode\n");
+ return SANE_STATUS_INVAL;
+ }
+
+ HP5400_DBG (DBG_MSG, "Setting BW/Colour state=%d\n", bwColourValue);
+
+ /*
+ * Now write it with the other panel settings back to the scanner.
+ *
+ */
+ if (SetColourBW(&s->HWParams, bwColourValue) != 0)
+ {
+ HP5400_DBG (DBG_ERR,
+ "sane_control_option: SANE_ACTION_SET_VALUE could not set colour/BW mode\n");
+ return SANE_STATUS_IO_ERROR;
+ }
+ break;
+ }
+
+ case optSensorCopyCount:
+ {
+ SANE_Word copyCount = *(SANE_Word *) pVal;
+ if (copyCount < 0)
+ {
+ copyCount = 0;
+ }
+ else if (copyCount > 99)
+ {
+ copyCount = 99;
+ }
+
+ HP5400_DBG (DBG_MSG, "Setting Copy Count=%d\n", copyCount);
+
+ /*
+ * Now write it with the other panel settings back to the scanner.
+ *
+ */
+ if (SetCopyCount(&s->HWParams, copyCount) != 0)
+ {
+ HP5400_DBG (DBG_ERR,
+ "sane_control_option: SANE_ACTION_SET_VALUE could not set copy count\n");
+ return SANE_STATUS_IO_ERROR;
+
+ }
+ break;
+ }
+
/*
case optLamp:
fVal = *(SANE_Bool *)pVal;
@@ -924,6 +1253,7 @@ sane_start (SANE_Handle h)
s->ScanParams.iLinesRead = 0;
s->fScanning = TRUE;
+ s->fCanceled = FALSE;
return SANE_STATUS_GOOD;
}
@@ -944,6 +1274,11 @@ sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
/* nothing has been read for the moment */
*len = 0;
+ if (!s->fScanning || s->fCanceled)
+ {
+ HP5400_DBG (DBG_MSG, "sane_read: we're not scanning.\n");
+ return SANE_STATUS_EOF;
+ }
/* if we read all the lines return EOF */
diff --git a/backend/kodakaio.c b/backend/kodakaio.c
index d5c2857..9a7a8b4 100644
--- a/backend/kodakaio.c
+++ b/backend/kodakaio.c
@@ -18,13 +18,13 @@
* The connection is now made in sane_start and ended in sane_cancel.
* 01/01/13 Now with adf, the scan can be padded to make up the full page length,
* or the page can terminate at the end of the paper. This is a selectable option.
- * 25/11/12 Using avahi now for net autodiscovery. Use configure option --enable-avahi
+ * 25/11/12 Using avahi now for net autodiscovery. Use configure option --with-avahi to make sure it's enabled
* 1/5/17 patched to use local pointer for avahi callback
*/
/*
Packages to add to a clean ubuntu install
-libavahi-common-dev
+libavahi-client-dev
libusb-dev
libsnmp-dev
@@ -32,13 +32,13 @@ convenient lines to paste
export SANE_DEBUG_KODAKAIO=20
for ubuntu prior to 12.10
-./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-avahi --without-api-spec BACKENDS="kodakaio test"
+./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var BACKENDS="kodakaio test"
for ubuntu 12.10
-./configure --prefix=/usr --libdir=/usr/lib/i386-linux-gnu --sysconfdir=/etc --localstatedir=/var --enable-avahi --without-api-spec BACKENDS="kodakaio test"
+./configure --prefix=/usr --libdir=/usr/lib/i386-linux-gnu --sysconfdir=/etc --localstatedir=/var BACKENDS="kodakaio test"
for ubuntu 14.10 up to at least 17.04
-./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu --sysconfdir=/etc --localstatedir=/var --enable-avahi --without-api-spec BACKENDS="kodakaio test"
+./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu --sysconfdir=/etc --localstatedir=/var BACKENDS="kodakaio test"
If you want to use the test backend, for example with sane-troubleshoot, you should enable it in /etc/sane.d/dll.conf
diff --git a/backend/kvs1025.c b/backend/kvs1025.c
index c0e1fa3..fc89d87 100644
--- a/backend/kvs1025.c
+++ b/backend/kvs1025.c
@@ -34,8 +34,8 @@
#include "../include/sane/sanei_debug.h"
-/* SANE backend operations, see Sane standard 1.04 documents (sane_dev.pdf)
- for details */
+/* SANE backend operations, see SANE Standard for details
+ https://sane-project.gitlab.io/standard/ */
/* Init the KV-S1025 SANE backend. This function must be called before any other
SANE function can be called. */
diff --git a/backend/kvs20xx_opt.c b/backend/kvs20xx_opt.c
index e4b841b..3e82764 100644
--- a/backend/kvs20xx_opt.c
+++ b/backend/kvs20xx_opt.c
@@ -736,8 +736,8 @@ kvs20xx_init_window (struct scanner *s, struct window *wnd, int wnd_id)
s->val[GAMMA_CORRECTION].s)];
wnd->mcd_lamp_dfeed_sens = str_index (lamp_list, s->val[LAMP].s) << 4 | 2;
- wnd->document_size = (paper != 0) << 7
- | s->val[LENGTHCTL].b << 6 | s->val[LANDSCAPE].b << 4 | paper_val[paper];
+ wnd->document_size = ((paper != 0) << 7) | (s->val[LENGTHCTL].b << 6)
+ | (s->val[LANDSCAPE].b << 4) | paper_val[paper];
wnd->ahead_deskew_dfeed_scan_area_fspeed_rshad = s->val[DBLFEED].b << 4
| s->val[FIT_TO_PAGE].b << 2;
diff --git a/backend/kvs40xx_opt.c b/backend/kvs40xx_opt.c
index c812f2c..8c37711 100644
--- a/backend/kvs40xx_opt.c
+++ b/backend/kvs40xx_opt.c
@@ -1344,9 +1344,9 @@ kvs40xx_init_window (struct scanner *s, struct window *wnd, int wnd_id)
str_index (lamp_list, s->val[LAMP].s) << 4 |
str_index (dfeed_sence_list, s->val[DFEED_SENCE].s);
- wnd->document_size = (paper != 0) << 7
- | s->val[LENGTHCTL].b << 6
- | s->val[LONG_PAPER].b << 5 | s->val[LANDSCAPE].b << 4 | paper_val[paper];
+ wnd->document_size = ((paper != 0) << 7) | (s->val[LENGTHCTL].b << 6)
+ | (s->val[LONG_PAPER].b << 5) | (s->val[LANDSCAPE].b << 4)
+ | paper_val[paper];
wnd->ahead_deskew_dfeed_scan_area_fspeed_rshad =
(s->val[DESKEW].b || s->val[CROP].b ? 2 : 0) << 5 | /*XXX*/
diff --git a/backend/mustek.c b/backend/mustek.c
index eafdb99..6a9aa86 100644
--- a/backend/mustek.c
+++ b/backend/mustek.c
@@ -4433,7 +4433,7 @@ init_options (Mustek_Scanner * s)
s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_PERCENT;
s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
s->opt[OPT_BRIGHTNESS].constraint.range = &percentage_range;
- if (!s->hw->flags & MUSTEK_FLAG_THREE_PASS)
+ if (!(s->hw->flags & MUSTEK_FLAG_THREE_PASS))
/* 1-pass scanners don't support brightness in multibit mode */
s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
s->val[OPT_BRIGHTNESS].w = 0;
diff --git a/backend/net.c b/backend/net.c
index df19192..4ad2e1b 100644
--- a/backend/net.c
+++ b/backend/net.c
@@ -67,7 +67,7 @@
#include <netinet/in.h>
#include <netdb.h> /* OS/2 needs this _after_ <netinet/in.h>, grrr... */
-#ifdef WITH_AVAHI
+#if WITH_AVAHI
# include <avahi-client/client.h>
# include <avahi-client/lookup.h>
@@ -695,7 +695,7 @@ do_authorization (Net_Device * dev, SANE_String resource)
}
-#ifdef WITH_AVAHI
+#if WITH_AVAHI
static void
net_avahi_resolve_callback (AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol,
AvahiResolverEvent event, const char *name, const char *type,
@@ -964,7 +964,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
first_device = NULL;
first_handle = NULL;
-#ifdef WITH_AVAHI
+#if WITH_AVAHI
net_avahi_init ();
#endif /* WITH_AVAHI */
@@ -1044,12 +1044,12 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
continue;
}
-#ifdef WITH_AVAHI
+#if WITH_AVAHI
avahi_threaded_poll_lock (avahi_thread);
#endif /* WITH_AVAHI */
DBG (2, "sane_init: trying to add %s\n", device_name);
add_device (device_name, 0);
-#ifdef WITH_AVAHI
+#if WITH_AVAHI
avahi_threaded_poll_unlock (avahi_thread);
#endif /* WITH_AVAHI */
}
@@ -1095,12 +1095,12 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
if (host[0] == '\0')
continue;
#endif /* ENABLE_IPV6 */
-#ifdef WITH_AVAHI
+#if WITH_AVAHI
avahi_threaded_poll_lock (avahi_thread);
#endif /* WITH_AVAHI */
DBG (2, "sane_init: trying to add %s\n", host);
add_device (host, 0);
-#ifdef WITH_AVAHI
+#if WITH_AVAHI
avahi_threaded_poll_unlock (avahi_thread);
#endif /* WITH_AVAHI */
}
@@ -1132,7 +1132,7 @@ sane_exit (void)
DBG (1, "sane_exit: exiting\n");
-#ifdef WITH_AVAHI
+#if WITH_AVAHI
net_avahi_cleanup ();
#endif /* WITH_AVAHI */
@@ -1518,11 +1518,11 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle)
DBG (1,
"sane_open: device %s not found, trying to register it anyway\n",
nd_name);
-#ifdef WITH_AVAHI
+#if WITH_AVAHI
avahi_threaded_poll_lock (avahi_thread);
#endif /* WITH_AVAHI */
status = add_device (nd_name, &dev);
-#ifdef WITH_AVAHI
+#if WITH_AVAHI
avahi_threaded_poll_unlock (avahi_thread);
#endif /* WITH_AVAHI */
if (status != SANE_STATUS_GOOD)
diff --git a/backend/pixma/.gitignore b/backend/pixma/.gitignore
new file mode 100644
index 0000000..fe87a57
--- /dev/null
+++ b/backend/pixma/.gitignore
@@ -0,0 +1 @@
+pixma_sane_options.[ch]
diff --git a/backend/pixma/pixma.c b/backend/pixma/pixma.c
index f763496..c32907c 100644
--- a/backend/pixma/pixma.c
+++ b/backend/pixma/pixma.c
@@ -1,6 +1,6 @@
/* SANE - Scanner Access Now Easy.
- Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de>
+ Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de>
Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org>
Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
@@ -67,6 +67,7 @@
# include "../include/sane/sanei_backend.h"
# include "../include/sane/sanei_config.h"
# include "../include/sane/sanei_jpeg.h"
+# include "../include/sane/sanei_usb.h"
#ifdef NDEBUG
# define PDBG(x)
@@ -91,7 +92,7 @@
*/
#include "pixma_sane_options.h"
-#define BUTTON_GROUP_SIZE ( opt_scan_resolution - opt_button_1 + 1 )
+#define BUTTON_GROUP_SIZE ( opt_adf_orientation - opt_button_1 + 1 )
#define BUTTON_GROUP_INDEX(x) ( x - opt_button_1 )
typedef struct pixma_sane_t
@@ -317,6 +318,9 @@ update_button_state (pixma_sane_t * ss, SANE_Int * info)
OVAL (opt_original).w = GET_EV_ORIGINAL(ev);
OVAL (opt_target).w = GET_EV_TARGET(ev);
OVAL (opt_scan_resolution).w = GET_EV_DPI(ev);
+ OVAL (opt_document_type).w = GET_EV_DOC(ev);
+ OVAL (opt_adf_status).w = GET_EV_STAT(ev);
+ OVAL (opt_adf_orientation).w = GET_EV_ORIENT(ev);
}
mark_all_button_options_cached(ss);
}
@@ -469,7 +473,7 @@ create_dpi_list (pixma_sane_t * ss)
|| ss->mode_map[OVAL (opt_mode).w] == PIXMA_SCAN_MODE_GRAY_16))
{ /* 48 bits flatbed */
/*PDBG (pixma_dbg (4, "*create_dpi_list***** 48 bits flatbed mode\n"));*/
- min_dpi = 150;
+ min_dpi = (cfg->min_xdpi_16) ? cfg->min_xdpi_16 : 75;
}
/* set j for min. dpi
@@ -541,6 +545,8 @@ control_scalar_option (pixma_sane_t * ss, SANE_Int n, SANE_Action a, void *v,
option_descriptor_t *opt = &(OPT_IN_CTX[n]);
SANE_Word val;
+ /* PDBG (pixma_dbg (4, "*control_scalar_option***** n = %u, a = %u\n", n, a)); */
+
switch (a)
{
case SANE_ACTION_GET_VALUE:
@@ -604,6 +610,8 @@ control_string_option (pixma_sane_t * ss, SANE_Int n, SANE_Action a, void *v,
const SANE_String_Const *slist = opt->sod.constraint.string_list;
SANE_String str = (SANE_String) v;
+ /* PDBG (pixma_dbg (4, "*control_string_option***** n = %u, a = %u\n", n, a)); */
+
if (opt->sod.constraint_type == SANE_CONSTRAINT_NONE)
{
switch (a)
@@ -656,6 +664,7 @@ static SANE_Status
control_option (pixma_sane_t * ss, SANE_Int n,
SANE_Action a, void *v, SANE_Int * info)
{
+ SANE_Option_Descriptor *sod = &SOD (n);
int result, i;
const pixma_config_t *cfg;
SANE_Int dummy;
@@ -673,25 +682,59 @@ control_option (pixma_sane_t * ss, SANE_Int n,
switch (n)
{
case opt_gamma_table:
- switch (a)
- {
- case SANE_ACTION_SET_VALUE:
- clamp_value (ss, n, v, info);
- for (i = 0; i != 4096; i++)
- ss->gamma_table[i] = *((SANE_Int *) v + i);
- break;
- case SANE_ACTION_GET_VALUE:
- for (i = 0; i != 4096; i++)
- *((SANE_Int *) v + i) = ss->gamma_table[i];
- break;
- case SANE_ACTION_SET_AUTO:
- pixma_fill_gamma_table (AUTO_GAMMA, ss->gamma_table,
- sizeof (ss->gamma_table));
- break;
- default:
- return SANE_STATUS_UNSUPPORTED;
- }
- return SANE_STATUS_GOOD;
+ {
+ int table_size = sod->size / sizeof (SANE_Word);
+ int byte_cnt = table_size == 1024 ? 2 : 1;
+
+ switch (a)
+ {
+ case SANE_ACTION_SET_VALUE:
+ PDBG (pixma_dbg (4, "*control_option***** opt_gamma_table: SANE_ACTION_SET_VALUE with %d values ***** \n", table_size));
+ clamp_value (ss, n, v, info);
+ if (byte_cnt == 1)
+ {
+ for (i = 0; i < table_size; i++)
+ ss->gamma_table[i] = *((SANE_Int *) v + i);
+ }
+ else
+ {
+ for (i = 0; i < table_size; i++)
+ {
+ ss->gamma_table[i * 2] = *((SANE_Int *) v + i);
+ ss->gamma_table[i * 2 + 1] = *((uint8_t *)((SANE_Int *) v + i) + 1);
+ }
+ }
+ /* PDBG (pixma_hexdump (4, (uint8_t *)v, table_size * 4)); */
+ /* PDBG (pixma_hexdump (4, ss->gamma_table, table_size * byte_cnt)); */
+ break;
+ case SANE_ACTION_GET_VALUE:
+ PDBG (pixma_dbg (4, "*control_option***** opt_gamma_table: SANE_ACTION_GET_VALUE ***** \n"));
+ if (byte_cnt == 1)
+ {
+ for (i = 0; i < table_size; i++)
+ *((SANE_Int *) v + i) = ss->gamma_table[i];
+ }
+ else
+ {
+ for (i = 0; i < table_size; i++)
+ {
+ *((SANE_Int *) v + i) = ss->gamma_table[i * 2];
+ *((uint8_t *)((SANE_Int *) v + i) + 1) = ss->gamma_table[i * 2 + 1];
+ }
+ }
+ break;
+ case SANE_ACTION_SET_AUTO:
+ PDBG (pixma_dbg (4, "*control_option***** opt_gamma_table: SANE_ACTION_SET_AUTO with gamma=%f ***** \n",
+ SANE_UNFIX (OVAL (opt_gamma).w)));
+ pixma_fill_gamma_table (SANE_UNFIX (OVAL (opt_gamma).w),
+ ss->gamma_table, table_size);
+ /* PDBG (pixma_hexdump (4, ss->gamma_table, table_size * byte_cnt)); */
+ break;
+ default:
+ return SANE_STATUS_UNSUPPORTED;
+ }
+ return SANE_STATUS_GOOD;
+ }
case opt_button_update:
if (a == SANE_ACTION_SET_VALUE)
@@ -709,6 +752,9 @@ control_option (pixma_sane_t * ss, SANE_Int n,
case opt_original:
case opt_target:
case opt_scan_resolution:
+ case opt_document_type:
+ case opt_adf_status:
+ case opt_adf_orientation:
/* poll scanner if option is not cached */
if (! ss->button_option_is_cached[ BUTTON_GROUP_INDEX(n) ] )
update_button_state (ss, info);
@@ -744,15 +790,24 @@ control_option (pixma_sane_t * ss, SANE_Int n,
{
if (enable_option (ss, opt_gamma_table, OVAL (opt_custom_gamma).b))
*info |= SANE_INFO_RELOAD_OPTIONS;
+ if (OVAL (opt_custom_gamma).b)
+ sane_control_option (ss, opt_gamma_table, SANE_ACTION_SET_AUTO,
+ NULL, NULL);
+
}
break;
case opt_gamma:
if (a == SANE_ACTION_SET_VALUE || a == SANE_ACTION_SET_AUTO)
{
- /* PDBG (pixma_dbg (4, "*control_option***** gamma = %f *\n",
- SANE_UNFIX (OVAL (opt_gamma).w))); */
+ int table_size = SOD (opt_gamma_table).size / sizeof(SANE_Word);
+ PDBG (pixma_dbg (4, "*control_option***** gamma = %f *\n",
+ SANE_UNFIX (OVAL (opt_gamma).w)));
+ PDBG (pixma_dbg (4, "*control_option***** table size = %d *\n",
+ (int)(SOD (opt_gamma_table).size / sizeof (SANE_Word))));
pixma_fill_gamma_table (SANE_UNFIX (OVAL (opt_gamma).w),
- ss->gamma_table, sizeof (ss->gamma_table));
+ ss->gamma_table, table_size);
+ /* PDBG (pixma_hexdump (4, ss->gamma_table,
+ table_size == 1024 ? 2048 : table_size)); */
}
break;
case opt_mode:
@@ -826,8 +881,8 @@ print_scan_param (int level, const pixma_scan_param_t * sp)
sp->line_size, sp->image_size, sp->channels, sp->depth);
pixma_dbg (level, " dpi=%ux%u offset=(%u,%u) dimension=%ux%u\n",
sp->xdpi, sp->ydpi, sp->x, sp->y, sp->w, sp->h);
- pixma_dbg (level, " gamma_table=%p source=%d\n", sp->gamma_table,
- sp->source);
+ pixma_dbg (level, " gamma=%f gamma_table=%p source=%d\n", sp->gamma,
+ sp->gamma_table, sp->source);
pixma_dbg (level, " adf-wait=%d\n", sp->adf_wait);
}
#endif
@@ -872,7 +927,8 @@ calc_scan_param (pixma_sane_t * ss, pixma_scan_param_t * sp)
sp->h = 1;
sp->tpu_offset_added = 0;
- sp->gamma_table = (OVAL (opt_custom_gamma).b) ? ss->gamma_table : NULL;
+ sp->gamma = SANE_UNFIX (OVAL (opt_gamma).w);
+ sp->gamma_table = ss->gamma_table;
sp->source = ss->source_map[OVAL (opt_source).w];
sp->mode = ss->mode_map[OVAL (opt_mode).w];
sp->adf_pageid = ss->page_count;
@@ -897,6 +953,8 @@ init_option_descriptors (pixma_sane_t * ss)
cfg = pixma_get_config (ss->s);
+ /* PDBG (pixma_dbg (4, "*init_option_descriptors*****\n")); */
+
/* setup range for the scan area. */
ss->xrange.min = SANE_FIX (0);
ss->xrange.max = SANE_FIX (cfg->width / 75.0 * 25.4);
@@ -944,11 +1002,32 @@ init_option_descriptors (pixma_sane_t * ss)
/* Enable options that are available only in some scanners. */
if (cfg->cap & PIXMA_CAP_GAMMA_TABLE)
{
+ SANE_Option_Descriptor *sod = &SOD (opt_gamma_table);
+
+ /* some scanners have a large gamma table with 4096 entries */
+ if (cfg->cap & PIXMA_CAP_GT_4096)
+ {
+ static const SANE_Range constraint_gamma_table_4096 = { 0,0xff,0 };
+ sod->desc = SANE_I18N("Gamma-correction table with 4096 entries. In color mode this option equally affects the red, green, and blue channels simultaneously (i.e., it is an intensity gamma table).");
+ sod->size = 4096 * sizeof(SANE_Word);
+ sod->constraint.range = &constraint_gamma_table_4096;
+ }
+
+ /* PDBG (pixma_dbg (4, "*%s***** PIXMA_CAP_GAMMA_TABLE ***** \n",
+ __func__)); */
+ /* PDBG (pixma_dbg (4, "%s: gamma_table_contraint.max = %d\n",
+ __func__, sod->constraint.range->max)); */
+ /* PDBG (pixma_dbg (4, "%s: gamma_table_size = %d\n",
+ __func__, sod->size / sizeof(SANE_Word))); */
+
+ /* activate option gamma */
enable_option (ss, opt_gamma, SANE_TRUE);
+ sane_control_option (ss, opt_gamma, SANE_ACTION_SET_AUTO,
+ NULL, NULL);
+ /* activate option custom gamma table */
enable_option (ss, opt_custom_gamma, SANE_TRUE);
sane_control_option (ss, opt_custom_gamma, SANE_ACTION_SET_AUTO,
- NULL, NULL);
- pixma_fill_gamma_table (AUTO_GAMMA, ss->gamma_table, 4096);
+ NULL, NULL);
}
enable_option (ss, opt_button_controlled,
((cfg->cap & PIXMA_CAP_EVENTS) != 0));
@@ -1597,6 +1676,7 @@ sane_exit (void)
sane_close (first_scanner);
cleanup_device_list ();
pixma_cleanup ();
+ sanei_usb_exit ();
}
SANE_Status
@@ -1624,7 +1704,11 @@ sane_open (SANE_String_Const name, SANE_Handle * h)
nscanners = pixma_find_scanners (conf_devices, SANE_FALSE);
if (nscanners == 0)
return SANE_STATUS_INVAL;
- if (name[0] == '\0')
+
+ /* also get device id if we replay a xml file
+ * otherwise name contains the xml filename
+ * and further replay will fail */
+ if (name[0] == '\0' || strstr (name, ".xml"))
name = pixma_get_device_id (0);
/* Have we already opened the scanner? */
@@ -1995,7 +2079,13 @@ sane_get_select_fd (SANE_Handle h, SANE_Int * fd)
return SANE_STATUS_GOOD;
}
-/*
+/* CAUTION!
+ * Remove generated files pixma_sane_options.[ch] after editing SANE option
+ * descriptors below OR do a 'make clean' OR manually generate them as described
+ * below.
+ * However, make drops the circular dependency and the files won't be generated
+ * again (see merge request sane-project/backends!491).
+
BEGIN SANE_Option_Descriptor
rem -------------------------------------------
@@ -2037,15 +2127,15 @@ type group
title Gamma
type bool custom-gamma
- default SANE_TRUE
+ default SANE_FALSE
title @SANE_TITLE_CUSTOM_GAMMA
desc @SANE_DESC_CUSTOM_GAMMA
cap soft_select soft_detect automatic inactive
-type int gamma-table[4096]
- constraint (0,255,0)
+type int gamma-table[1024]
+ constraint (0,0xffff,0)
title @SANE_TITLE_GAMMA_VECTOR
- desc @SANE_DESC_GAMMA_VECTOR
+ desc Gamma-correction table with 1024 entries. In color mode this option equally affects the red, green, and blue channels simultaneously (i.e., it is an intensity gamma table).
cap soft_select soft_detect automatic inactive
type fixed gamma
@@ -2128,6 +2218,21 @@ type int scan-resolution
title Scan resolution
cap soft_detect advanced
+type int document-type
+ default 0
+ title Document type
+ cap soft_detect advanced
+
+type int adf-status
+ default 0
+ title ADF status
+ cap soft_detect advanced
+
+type int adf-orientation
+ default 0
+ title ADF orientation
+ cap soft_detect advanced
+
rem -------------------------------------------
type group
title Extras
@@ -2150,7 +2255,7 @@ type int adf-wait
default 0
constraint (0,3600,1)
title ADF Waiting Time
- desc When set, the scanner searches the waiting time in seconds for a new document inserted into the automatic document feeder.
+ desc When set, the scanner waits upto the specified time in seconds for a new document inserted into the automatic document feeder.
cap soft_select soft_detect automatic inactive
rem -------------------------------------------
diff --git a/backend/pixma/pixma.h b/backend/pixma/pixma.h
index c2df3cc..c9026a7 100644
--- a/backend/pixma/pixma.h
+++ b/backend/pixma/pixma.h
@@ -1,6 +1,6 @@
/* SANE - Scanner Access Now Easy.
- Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de>
+ Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de>
Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org>
Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
@@ -119,8 +119,8 @@ typedef uint32_t uint32_t;
/** \name Version of the driver */
/**@{*/
#define PIXMA_VERSION_MAJOR 0
-#define PIXMA_VERSION_MINOR 27
-#define PIXMA_VERSION_BUILD 0
+#define PIXMA_VERSION_MINOR 28
+#define PIXMA_VERSION_BUILD 5
/**@}*/
/** \name Error codes */
@@ -158,6 +158,10 @@ typedef uint32_t uint32_t;
#define PIXMA_CAP_TPUIR ((1 << 11) | PIXMA_CAP_TPU)
#define PIXMA_CAP_ADF_WAIT (1 << 12)
#define PIXMA_CAP_ADF_JPEG (1 << 13)
+#define PIXMA_CAP_GT_4096 (1 << 14) /* gamma table has 4096 8-bit values
+ * only generation 1 scanners
+ * usually gamma table has 1024 16-bit values
+ */
#define PIXMA_CAP_EXPERIMENT (1 << 31)
/**@}*/
@@ -167,13 +171,19 @@ typedef uint32_t uint32_t;
#define PIXMA_EV_ACTION_MASK (0xffffff)
#define PIXMA_EV_BUTTON1 (1 << 24)
#define PIXMA_EV_BUTTON2 (2 << 24)
-#define PIXMA_EV_TARGET_MASK (0xff)
-#define PIXMA_EV_ORIGINAL_MASK (0xff00)
-#define PIXMA_EV_DPI_MASK (0xff0000)
+#define PIXMA_EV_TARGET_MASK (0x0f)
+#define PIXMA_EV_ORIGINAL_MASK (0x0f00)
+#define PIXMA_EV_DPI_MASK (0x0f0000)
+#define PIXMA_EV_DOC_MASK (0xf000)
+#define PIXMA_EV_STAT_MASK (0xf00000)
+#define PIXMA_EV_ORIENT_MASK (0xf0)
#define GET_EV_TARGET(x) (x & PIXMA_EV_TARGET_MASK)
#define GET_EV_ORIGINAL(x) ( (x & PIXMA_EV_ORIGINAL_MASK) >> 8 )
#define GET_EV_DPI(x) ( (x & PIXMA_EV_DPI_MASK) >> 16 )
+#define GET_EV_DOC(x) ( (x & PIXMA_EV_DOC_MASK) >> 12 )
+#define GET_EV_STAT(x) ( (x & PIXMA_EV_STAT_MASK) >> 20 )
+#define GET_EV_ORIENT(x) ( (x & PIXMA_EV_ORIENT_MASK) >> 4 )
/**@}*/
/** @} end of API group */
@@ -340,6 +350,9 @@ struct pixma_scan_param_t
* specified by subdriver will be used. */
const uint8_t *gamma_table;
+ /** value for auto generated gamma table */
+ double gamma;
+
/** \see #pixma_paper_source_t */
pixma_paper_source_t source;
@@ -365,7 +378,8 @@ struct pixma_config_t
uint16_t pid; /**< USB Product ID */
unsigned iface; /**< USB Interface number */
const pixma_scan_ops_t *ops; /**< Subdriver ops */
- unsigned min_xdpi; /**< Minimum horizontal resolution[DPI] */
+ unsigned min_xdpi; /**< Minimum horizontal resolution[DPI] */
+ unsigned min_xdpi_16;/**< Minimum horizontal resolution[DPI] for 16-bit scans */
unsigned xdpi; /**< Maximum horizontal resolution[DPI] */
unsigned ydpi; /**< Maximum vertical resolution[DPI] */
unsigned adftpu_min_dpi; /**< Maximum horizontal resolution[DPI] for adf/tpu
diff --git a/backend/pixma/pixma_bjnp.c b/backend/pixma/pixma_bjnp.c
index 34ba918..4e83714 100644
--- a/backend/pixma/pixma_bjnp.c
+++ b/backend/pixma/pixma_bjnp.c
@@ -109,6 +109,13 @@
#ifndef SSIZE_MAX
# define SSIZE_MAX LONG_MAX
#endif
+#ifndef HOST_NAME_MAX
+# ifdef _POSIX_HOST_NAME_MAX
+# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
+# else
+# define HOST_NAME_MAX 255
+# endif
+#endif
/* static data */
static bjnp_device_t device[BJNP_NO_DEVICES];
@@ -454,69 +461,6 @@ determine_scanner_serial (const char *hostname, const char * mac_address, char *
}
static int
-bjnp_open_tcp (int devno)
-{
- int sock;
- int val;
- bjnp_sockaddr_t *addr = device[devno].addr;
- char host[BJNP_HOST_MAX];
- int port;
- int connect_timeout = BJNP_TIMEOUT_TCP_CONNECT;
-
- get_address_info( addr, host, &port);
- PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_open_tcp: Setting up a TCP socket, dest: %s port %d\n",
- host, port ) );
-
- if ((sock = socket (get_protocol_family( addr ) , SOCK_STREAM, 0)) < 0)
- {
- PDBG (bjnp_dbg (LOG_CRIT, "bjnp_open_tcp: ERROR - Can not create socket: %s\n",
- strerror (errno)));
- return -1;
- }
-
- val = 1;
- setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val));
-
-#if 0
- val = 1;
- setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof (val));
-
- val = 1;
-#endif
-
- /*
- * Using TCP_NODELAY improves responsiveness, especially on systems
- * with a slow loopback interface...
- */
-
- val = 1;
- setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
-
-/*
- * Close this socket when starting another process...
- */
-
- fcntl (sock, F_SETFD, FD_CLOEXEC);
-
- while (connect_timeout > 0)
- {
- if (connect
- (sock, &(addr->addr), sa_size(device[devno].addr)) == 0)
- {
- device[devno].tcp_socket = sock;
- return 0;
- }
- PDBG (bjnp_dbg( LOG_INFO, "bjnp_open_tcp: INFO - Can not yet connect over TCP to scanner: %s, retrying\n",
- strerror(errno)));
- usleep(BJNP_TCP_CONNECT_INTERVAL * BJNP_USLEEP_MS);
- connect_timeout = connect_timeout - BJNP_TCP_CONNECT_INTERVAL;
- }
- PDBG (bjnp_dbg
- (LOG_CRIT, "bjnp_open_tcp: ERROR - Can not connect to scanner, giving up!"));
- return -1;
-}
-
-static int
split_uri (const char *devname, char *method, char *host, char *port,
char *args)
{
@@ -1565,6 +1509,7 @@ bjnp_init_device_structure(int dn, bjnp_sockaddr_t *sa, bjnp_protocol_defs_t *pr
#endif
device[dn].protocol = protocol_defs->protocol_version;
device[dn].protocol_string = protocol_defs->proto_string;
+ device[dn].single_tcp_session = protocol_defs->single_tcp_session;
device[dn].tcp_socket = -1;
device[dn].addr = (bjnp_sockaddr_t *) malloc(sizeof ( bjnp_sockaddr_t) );
@@ -1694,6 +1639,98 @@ bjnp_recv_data (int devno, SANE_Byte * buffer, size_t start_pos, size_t * len)
return SANE_STATUS_GOOD;
}
+static int
+bjnp_open_tcp (int devno)
+{
+ int sock;
+ int val;
+ char my_hostname[HOST_NAME_MAX];
+ char pid_str[64];
+ bjnp_sockaddr_t *addr = device[devno].addr;
+ char host[BJNP_HOST_MAX];
+ int port;
+ int connect_timeout = BJNP_TIMEOUT_TCP_CONNECT;
+
+ if (device[devno].tcp_socket != -1)
+ {
+ PDBG (bjnp_dbg( LOG_DEBUG, "bjnp_open_tcp: socket alreeady opened, nothing to do\n"));
+ return 0;
+ }
+ get_address_info( addr, host, &port);
+ PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_open_tcp: Setting up a TCP socket, dest: %s port %d\n",
+ host, port ) );
+
+ gethostname (my_hostname, HOST_NAME_MAX);
+ my_hostname[HOST_NAME_MAX - 1] = '\0';
+ sprintf (pid_str, "Process ID = %d", getpid ());
+ bjnp_send_job_details (devno, my_hostname, getusername (), pid_str);
+
+ if ((sock = socket (get_protocol_family( addr ) , SOCK_STREAM, 0)) < 0)
+ {
+ PDBG (bjnp_dbg (LOG_CRIT, "bjnp_open_tcp: ERROR - Can not create socket: %s\n",
+ strerror (errno)));
+ return -1;
+ }
+
+ val = 1;
+ setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val));
+
+#if 0
+ val = 1;
+ setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof (val));
+
+ val = 1;
+#endif
+
+ /*
+ * Using TCP_NODELAY improves responsiveness, especially on systems
+ * with a slow loopback interface...
+ */
+
+ val = 1;
+ setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val));
+
+/*
+ * Close this socket when starting another process...
+ */
+
+ fcntl (sock, F_SETFD, FD_CLOEXEC);
+
+ while (connect_timeout > 0)
+ {
+ if (connect
+ (sock, &(addr->addr), sa_size(device[devno].addr)) == 0)
+ {
+ device[devno].tcp_socket = sock;
+ PDBG( bjnp_dbg(LOG_INFO, "bjnp_open_tcp: created socket %d\n", sock));
+ return 0;
+ }
+ PDBG (bjnp_dbg( LOG_INFO, "bjnp_open_tcp: INFO - Can not yet connect over TCP to scanner: %s, retrying\n",
+ strerror(errno)));
+ usleep(BJNP_TCP_CONNECT_INTERVAL * BJNP_USLEEP_MS);
+ connect_timeout = connect_timeout - BJNP_TCP_CONNECT_INTERVAL;
+ }
+ PDBG (bjnp_dbg
+ (LOG_CRIT, "bjnp_open_tcp: ERROR - Can not connect to scanner, giving up!"));
+ return -1;
+}
+
+static void bjnp_close_tcp(int devno)
+{
+ if ( device[devno].tcp_socket != -1)
+ {
+ PDBG( bjnp_dbg( LOG_INFO, "bjnp_close_tcp - closing tcp-socket %d\n", device[devno].tcp_socket));
+ bjnp_finish_job (devno);
+ close (device[devno].tcp_socket);
+ device[devno].tcp_socket = -1;
+ }
+ else
+ {
+ PDBG( bjnp_dbg( LOG_INFO, "bjnp_close_tcp: socket not open, nothing to do.\n"));
+ }
+ device[devno].open = 0;
+}
+
static BJNP_Status
bjnp_allocate_device (SANE_String_Const devname,
SANE_Int * dn, char *resulting_host)
@@ -1762,7 +1799,7 @@ bjnp_allocate_device (SANE_String_Const devname,
if (result != 0 )
{
PDBG (bjnp_dbg (LOG_CRIT, "bjnp_allocate_device: ERROR - Cannot resolve host: %s port %s\n", host, port));
- return SANE_STATUS_INVAL;
+ return BJNP_STATUS_INVAL;
}
/* Check if a device number is already allocated to any of the scanner's addresses */
@@ -2273,6 +2310,13 @@ sanei_bjnp_open (SANE_String_Const devname, SANE_Int * dn)
if ( (result != BJNP_STATUS_GOOD) && (result != BJNP_STATUS_ALREADY_ALLOCATED ) ) {
return SANE_STATUS_INVAL;
}
+
+ if (device[*dn].single_tcp_session && bjnp_open_tcp (*dn) != 0)
+ {
+ PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_opening TCP connection failed.\n\n"));
+ return SANE_STATUS_INVAL;
+ }
+ PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_open done.\n\n"));
return SANE_STATUS_GOOD;
}
@@ -2286,8 +2330,8 @@ sanei_bjnp_close (SANE_Int dn)
{
PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_close(%d):\n", dn));
- device[dn].open = 0;
- sanei_bjnp_deactivate(dn);
+ bjnp_close_tcp( dn );
+ PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_close done.\n\n"));
}
/** Activate BJNP device connection
@@ -2298,21 +2342,13 @@ sanei_bjnp_close (SANE_Int dn)
SANE_Status
sanei_bjnp_activate (SANE_Int dn)
{
- char hostname[256];
- char pid_str[64];
-
PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_activate (%d)\n", dn));
- gethostname (hostname, 256);
- hostname[255] = '\0';
- sprintf (pid_str, "Process ID = %d", getpid ());
-
- bjnp_send_job_details (dn, hostname, getusername (), pid_str);
-
- if (bjnp_open_tcp (dn) != 0)
+ if (!(device[dn].single_tcp_session) && bjnp_open_tcp (dn) != 0)
{
+ PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_activate: open TCP connection failed.\n\n"));
return SANE_STATUS_INVAL;
}
-
+ PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_activate done.\n\n"));
return SANE_STATUS_GOOD;
}
@@ -2325,12 +2361,11 @@ SANE_Status
sanei_bjnp_deactivate (SANE_Int dn)
{
PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_deactivate (%d)\n", dn));
- if ( device[dn].tcp_socket != -1)
- {
- bjnp_finish_job (dn);
- close (device[dn].tcp_socket);
- device[dn].tcp_socket = -1;
- }
+ if (!device[dn].single_tcp_session)
+ {
+ bjnp_close_tcp(dn);
+ }
+ PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_deactivate done.\n\n"));
return SANE_STATUS_GOOD;
}
diff --git a/backend/pixma/pixma_bjnp_private.h b/backend/pixma/pixma_bjnp_private.h
index edfb330..19ba496 100644
--- a/backend/pixma/pixma_bjnp_private.h
+++ b/backend/pixma/pixma_bjnp_private.h
@@ -131,13 +131,14 @@ typedef struct
int default_port;
char * proto_string;
char * method_string;
+ int single_tcp_session;
} bjnp_protocol_defs_t;
bjnp_protocol_defs_t bjnp_protocol_defs[] =
{
- {PROTOCOL_BJNP, BJNP_PORT_SCAN,"BJNP", "bjnp"},
- {PROTOCOL_MFNP, MFNP_PORT_SCAN,"MFNP", "mfnp"},
- {PROTOCOL_NONE, -1, NULL, NULL}
+ {PROTOCOL_BJNP, BJNP_PORT_SCAN,"BJNP", "bjnp", SANE_FALSE},
+ {PROTOCOL_MFNP, MFNP_PORT_SCAN,"MFNP", "mfnp", SANE_TRUE},
+ {PROTOCOL_NONE, -1, NULL, NULL, SANE_FALSE}
};
/* commands */
@@ -346,9 +347,10 @@ typedef struct device_s
{
int open; /* connection to scanner is opened */
- /* protocol version */
+ /* protocol information */
int protocol;
char *protocol_string;
+ char single_tcp_session;
/* sockets */
diff --git a/backend/pixma/pixma_common.c b/backend/pixma/pixma_common.c
index 7b7ecec..436311a 100644
--- a/backend/pixma/pixma_common.c
+++ b/backend/pixma/pixma_common.c
@@ -1,6 +1,6 @@
/* SANE - Scanner Access Now Easy.
- Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de>
+ Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de>
Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org>
Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
@@ -48,11 +48,18 @@
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
+#include <ctype.h>
#include <math.h> /* pow(C90) */
#include <sys/time.h> /* gettimeofday(4.3BSD) */
#include <unistd.h> /* usleep */
+#if defined(HAVE_LIBXML2)
+# include <libxml/parser.h>
+#else
+# error "The pixma backend requires libxml2"
+#endif
+
#include "pixma_rename.h"
#include "pixma_common.h"
#include "pixma_io.h"
@@ -143,6 +150,24 @@ pixma_hexdump (int level, const void *d_, unsigned len)
p++;
}
}
+ for (c = 0; c < 4; c++)
+ {
+ p[0] = ' ';
+ p++;
+ }
+ for (c = 0; c != 16 && (ofs + c) < plen; c++)
+ {
+ if (isprint(d[ofs + c]))
+ p[0] = d[ofs + c];
+ else
+ p[0] = '.';
+ p++;
+ if (c == 7)
+ {
+ p[0] = ' ';
+ p++;
+ }
+ }
p[0] = '\0';
pixma_dbg (level, "%s\n", line);
ofs += c;
@@ -335,7 +360,7 @@ pixma_r_to_ir (uint8_t * gptr, uint8_t * sptr, unsigned w, unsigned c)
/* convert 24/48 bit RGB to 8/16 bit grayscale
*
- * Formular: g = (R + G + B) / 3
+ * Formular: Y' = 0,2126 R' + 0,7152 G' + 0,0722 B'
*
* sptr: source color scale buffer
* gptr: destination gray scale buffer
@@ -345,19 +370,28 @@ pixma_r_to_ir (uint8_t * gptr, uint8_t * sptr, unsigned w, unsigned c)
uint8_t *
pixma_rgb_to_gray (uint8_t * gptr, uint8_t * sptr, unsigned w, unsigned c)
{
- unsigned i, j, g;
+ unsigned i, g;
/* PDBG (pixma_dbg (4, "*pixma_rgb_to_gray*****\n")); */
for (i = 0; i < w; i++)
{
- for (j = 0, g = 0; j < 3; j++)
- {
- g += *sptr++;
- if (c == 6) g += (*sptr++ << 8); /* 48 bit RGB: high byte */
+ if (c == 6)
+ { /* 48 bit RGB */
+ unsigned r = sptr[0] + (sptr[1] << 8);
+ unsigned y = sptr[2] + (sptr[3] << 8);
+ unsigned b = sptr[4] + (sptr[5] << 8);
+
+ g = (r * 2126) + (y * 7152) + (b * 722);
+ sptr += 6;
}
+ else
+ { /* 24 bit RGB */
+ g = (sptr[0] * 2126) + (sptr[1] * 7152) + (sptr[2] * 722);
+ sptr += 3;
+ }
+ g /= 10000; /* 8 and 16 bit gray */
- g /= 3; /* 8 or 16 bit gray */
*gptr++ = g;
if (c == 6) *gptr++ = (g >> 8); /* 16 bit gray: high byte */
}
@@ -846,7 +880,7 @@ pixma_scan (pixma_t * s, pixma_scan_param_t * sp)
sp->line_size, sp->image_size, sp->channels, sp->depth);
pixma_dbg (3, " dpi=%ux%u offset=(%u,%u) dimension=%ux%u\n",
sp->xdpi, sp->ydpi, sp->x, sp->y, sp->w, sp->h);
- pixma_dbg (3, " gamma_table=%p source=%d\n", sp->gamma_table, sp->source);
+ pixma_dbg (3, " gamma=%f gamma_table=%p source=%d\n", sp->gamma, sp->gamma_table, sp->source);
pixma_dbg (3, " threshold=%d threshold_curve=%d\n", sp->threshold, sp->threshold_curve);
pixma_dbg (3, " adf-wait=%d\n", sp->adf_wait);
pixma_dbg (3, " ADF page count: %d\n", sp->adf_pageid);
@@ -1152,14 +1186,35 @@ pixma_get_config (pixma_t * s)
void
pixma_fill_gamma_table (double gamma, uint8_t * table, unsigned n)
{
- int i;
+ unsigned i;
double r_gamma = 1.0 / gamma;
- double out_scale = 255.0;
double in_scale = 1.0 / (n - 1);
- for (i = 0; (unsigned) i != n; i++)
+ /* 8-bits gamma table
+ * for generation 1 scanners
+ */
+ if (n == 4096)
+ {
+ double out_scale = 255.0;
+
+ for (i = 0; (unsigned) i != n; i++)
+ {
+ table[i] = (int) (out_scale * pow (i * in_scale, r_gamma) + 0.5);
+ }
+ }
+
+ /* 16-bits gamma table */
+ else
{
- table[i] = (int) (out_scale * pow (i * in_scale, r_gamma) + 0.5);
+ double out_scale = 65535.0;
+ uint16_t value;
+
+ for (i = 0; i < n; i++)
+ {
+ value = (uint16_t) (out_scale * pow (i * in_scale, r_gamma) + 0.5);
+ table[2 * i] = (uint8_t) (value & 0xff);
+ table[2 * i + 1] = (uint8_t) (value >> 8);
+ }
}
}
@@ -1185,3 +1240,97 @@ pixma_get_device_status (pixma_t * s, pixma_device_status_t * status)
memset (status, 0, sizeof (*status));
return s->ops->get_status (s, status);
}
+
+static const char *
+format_xml_response(const char *resp_details)
+{
+ if (strcmp(resp_details, "DeviceBusy") == 0)
+ /* https://cromwell-intl.com/open-source/canon-pixma-printer-scanner.html */
+ return "DeviceBusy - Device not initialized (yet). " \
+ "Please check the USB power, try a different port or install the Ink Cartridges if the device supports them.";
+ else if (strcmp(resp_details, "ScannerCarriageLockError") == 0)
+ return "ScannerCarriageLockError - Please consult the manual to unlock the Carriage Lock.";
+ else if (strcmp(resp_details, "PCScanning") == 0)
+ return "PCScanning - Previous scan attempt was not completed. Try disconnecting and reconnecting the scanner. " \
+ "If the problem persists, consider reporting it as a bug at http://www.sane-project.org/bugs.html.";
+ else if (strcmp(resp_details, "DeviceCheckError") == 0)
+ return "DeviceCheckError - Device detected a fault. Contact the repair center.";
+ else
+ return resp_details;
+}
+
+int
+pixma_parse_xml_response(const char *xml_message)
+{
+ int status = PIXMA_EPROTO;
+ xmlDoc *doc = NULL;
+ xmlNode *node = NULL;
+ xmlChar *content = NULL;
+
+ doc = xmlReadMemory(xml_message, strlen(xml_message), "mem:device-resp.xml", NULL, 0);
+ if (doc == NULL) {
+ PDBG(pixma_dbg(10, "unable to parse xml response\n"));
+ status = PIXMA_EINVAL;
+ goto clean;
+ }
+
+ node = xmlDocGetRootElement(doc);
+ if (node == NULL) {
+ status = PIXMA_EPROTO;
+ goto clean;
+ }
+
+ /* /cmd */
+ for (; node; node = node->next) {
+ if (strcmp((const char*)node->name, "cmd") == 0)
+ break;
+ }
+ if (!node) {
+ status = PIXMA_EPROTO;
+ goto clean;
+ }
+
+ /* /cmd/contents */
+ for (node = node->children; node; node = node->next) {
+ if (strcmp((const char*)node->name, "contents") == 0)
+ break;
+ }
+ if (!node) {
+ status = PIXMA_EPROTO;
+ goto clean;
+ }
+
+ /* /cmd/contents/param_set */
+ for (node = node->children; node; node = node->next) {
+ if (strcmp((const char*)node->name, "param_set") == 0)
+ break;
+ }
+ if (!node) {
+ status = PIXMA_EPROTO;
+ goto clean;
+ }
+
+ /* /cmd/contents/param_set/response... */
+ for (node = node->children; node; node = node->next)
+ {
+ if (strcmp((const char*)node->name, "response") == 0) {
+ content = xmlNodeGetContent(node);
+ if (strcmp((const char*)content, "OK") == 0)
+ status = PIXMA_STATUS_OK;
+ else
+ status = PIXMA_EINVAL;
+ xmlFree(content);
+ } else if (strcmp((const char*)node->name, "response_detail") == 0) {
+ content = xmlNodeGetContent(node);
+ if (strlen((const char*)content) > 0) {
+ PDBG(pixma_dbg(0, "device response: %s\n",
+ format_xml_response((const char*)content)));
+ }
+ xmlFree(content);
+ }
+ }
+
+clean:
+ xmlFreeDoc(doc);
+ return status;
+}
diff --git a/backend/pixma/pixma_common.h b/backend/pixma/pixma_common.h
index c0ed4ba..3e4e5bd 100644
--- a/backend/pixma/pixma_common.h
+++ b/backend/pixma/pixma_common.h
@@ -1,6 +1,6 @@
/* SANE - Scanner Access Now Easy.
- Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de>
+ Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de>
Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
This file is part of the SANE package.
@@ -205,6 +205,7 @@ uint8_t *pixma_newcmd (pixma_cmdbuf_t *, unsigned cmd,
int pixma_exec (pixma_t *, pixma_cmdbuf_t *);
int pixma_exec_short_cmd (pixma_t *, pixma_cmdbuf_t *, unsigned cmd);
int pixma_map_status_errno (unsigned status);
+int pixma_parse_xml_response(const char *xml_message);
/**@}*/
#define pixma_fill_checksum(start, end) do { \
diff --git a/backend/pixma/pixma_imageclass.c b/backend/pixma/pixma_imageclass.c
index ce0c37d..be483b2 100644
--- a/backend/pixma/pixma_imageclass.c
+++ b/backend/pixma/pixma_imageclass.c
@@ -1,6 +1,6 @@
/* SANE - Scanner Access Now Easy.
- Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de>
+ Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de>
Copyright (C) 2007-2009 Nicolas Martin, <nicols-guest at alioth dot debian dot org>
Copyright (C) 2008 Dennis Lou, dlou 99 at yahoo dot com
@@ -105,6 +105,7 @@
#define MF220_PID 0x27a8
#define MF210_PID 0x27a9
#define MF620_PID 0x27b4
+#define MF720_PID 0x27b5
#define MF410_PID 0x27c0
#define MF510_PID 0x27c2
#define MF230_PID 0x27d1
@@ -122,6 +123,7 @@
#define MF743_PID 0x27fc
#define MF640_PID 0x27fe
#define MF645_PID 0x27fd
+#define MF440_PID 0x2823
enum iclass_state_t
@@ -915,7 +917,7 @@ static const pixma_scan_ops_t pixma_iclass_ops = {
0x04a9, pid, /* vid pid */ \
1, /* iface */ \
&pixma_iclass_ops, /* ops */ \
- 0, /* min_xdpi not used in this subdriver */ \
+ 0, 0, /* min_xdpi & min_xdpi_16 not used in this subdriver */ \
dpi, dpi, /* xdpi, ydpi */ \
0, /* adftpu_min_dpi not used in this subdriver */ \
adftpu_max_dpi, /* adftpu_max_dpi */ \
@@ -961,6 +963,7 @@ const pixma_config_t pixma_iclass_devices[] = {
DEV ("Canon i-SENSYS MF220 Series", "MF220", MF220_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* max. w = 216mm */
DEV ("Canon i-SENSYS MF210 Series", "MF210", MF210_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), /* max. w = 216mm */
DEV ("Canon i-SENSYS MF620 Series", "MF620", MF620_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF),
+ DEV ("Canon i-SENSYS MF720 Series", "MF720", MF720_PID, 600, 300, 637, 877, PIXMA_CAP_ADFDUP),
DEV ("Canon i-SENSYS MF410 Series", "MF410", MF410_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* max. w = 216mm */
DEV ("Canon i-SENSYS MF510 Series", "MF510", MF510_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
DEV ("Canon i-SENSYS MF230 Series", "MF230", MF230_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), /* max. w = 216mm */
@@ -973,7 +976,7 @@ const pixma_config_t pixma_iclass_devices[] = {
DEV ("Canon imageCLASS MF634C", "MF632C/634C", MF634_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP),
DEV ("Canon imageCLASS MF733C", "MF731C/733C", MF731_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* however, we need this for ethernet/wifi */
DEV ("Canon imageCLASS D570", "D570", D570_PID, 600, 0, 640, 877, 0),
- DEV ("Canon i-SENSYS MF110 Series", "MF110", MF110_PID, 600, 0, 640, 1050, 0),
+ DEV ("Canon i-SENSYS MF110/910 Series", "MF110", MF110_PID, 600, 0, 640, 1050, 0),
DEV ("Canon i-SENSYS MF520 Series", "MF520", MF520_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
DEV ("Canon i-SENSYS MF420 Series", "MF420", MF420_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
DEV ("Canon i-SENSYS MF260 Series", "MF260", MF260_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
@@ -981,5 +984,6 @@ const pixma_config_t pixma_iclass_devices[] = {
DEV ("Canon i-SENSYS MF741C/743C", "MF741C/743C", MF743_PID, 600, 300, 640, 1050, PIXMA_CAP_ADFDUP), /* ADFDUP restricted to 300dpi */
DEV ("Canon i-SENSYS MF640 Series", "MF642C/643C/644C", MF640_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
DEV ("Canon i-SENSYS MF645C", "MF645C", MF645_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), /* max. w = 216mm */
+ DEV ("Canon i-SENSYS MF440 Series", "MF440", MF440_PID, 600, 300, 637, 877, PIXMA_CAP_ADFDUP),
DEV (NULL, NULL, 0, 0, 0, 0, 0, 0)
};
diff --git a/backend/pixma/pixma_io_sanei.c b/backend/pixma/pixma_io_sanei.c
index c30b404..c7b7a29 100644
--- a/backend/pixma/pixma_io_sanei.c
+++ b/backend/pixma/pixma_io_sanei.c
@@ -1,7 +1,7 @@
/* SANE - Scanner Access Now Easy.
* For limitations, see function sanei_usb_get_vendor_product().
- Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de>
+ Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de>
Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
This file is part of the SANE package.
diff --git a/backend/pixma/pixma_mp150.c b/backend/pixma/pixma_mp150.c
index 3973702..b438c1b 100644
--- a/backend/pixma/pixma_mp150.c
+++ b/backend/pixma/pixma_mp150.c
@@ -1,6 +1,6 @@
/* SANE - Scanner Access Now Easy.
- Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de>
+ Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de>
Copyright (C) 2007-2009 Nicolas Martin, <nicols-guest at alioth dot debian dot org>
Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
@@ -85,7 +85,6 @@
4096 = size of gamma table. 24 = header + checksum */
#define IMAGE_BLOCK_SIZE (512*1024)
#define CMDBUF_SIZE (4096 + 24)
-#define DEFAULT_GAMMA 2.0 /***** Gamma different from 1.0 is potentially impacting color profile generation *****/
#define UNKNOWN_PID 0xffff
@@ -282,8 +281,10 @@
#define TS8230_PID 0x185b
#define TS9580_PID 0x185d
#define TR9530_PID 0x185e
+#define G7000_PID 0x1863
#define G6000_PID 0x1865
#define G6080_PID 0x1866
+#define GM4000_PID 0x1869
#define XK80_PID 0x1873
#define TS5300_PID 0x188b
#define TS5380_PID 0x188c
@@ -321,8 +322,6 @@
<ivec:param_set servicetype=\"scan\"><ivec:jobID>00000001</ivec:jobID>\
</ivec:param_set></ivec:contents></cmd>"
-#define XML_OK "<ivec:response>OK</ivec:response>"
-
enum mp150_state_t
{
state_idle,
@@ -460,7 +459,7 @@ send_xml_dialog (pixma_t * s, const char * xml_message)
PDBG (pixma_dbg (10, "XML message sent to scanner:\n%s\n", xml_message));
PDBG (pixma_dbg (10, "XML response back from scanner:\n%s\n", mp->cb.buf));
- return (strcasestr ((const char *) mp->cb.buf, XML_OK) != NULL);
+ return pixma_parse_xml_response((const char*)mp->cb.buf) == PIXMA_STATUS_OK;
}
static int
@@ -567,42 +566,45 @@ send_gamma_table (pixma_t * s)
const uint8_t *lut = s->param->gamma_table;
uint8_t *data;
- if (mp->generation == 1)
+ if (s->cfg->cap & PIXMA_CAP_GT_4096)
{
data = pixma_newcmd (&mp->cb, cmd_gamma, 4096 + 8, 0);
data[0] = (s->param->channels == 3) ? 0x10 : 0x01;
pixma_set_be16 (0x1004, data + 2);
if (lut)
- memcpy (data + 4, lut, 4096);
+ {
+ /* PDBG (pixma_dbg (4, "*send_gamma_table***** Use 4096 bytes from LUT ***** \n")); */
+ /* PDBG (pixma_hexdump (4, lut, 4096)); */
+ memcpy (data + 4, lut, 4096);
+ }
else
- pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 4096);
+ {
+ /* fallback: we should never see this */
+ PDBG (pixma_dbg (4, "*send_gamma_table***** Generate 4096 bytes Table with %f ***** \n",
+ s->param->gamma));
+ pixma_fill_gamma_table (s->param->gamma, data + 4, 4096);
+ /* PDBG (pixma_hexdump (4, data + 4, 4096)); */
+ }
}
else
{
- /* FIXME: Gamma table for 2nd generation: 1024 * uint16_le */
- data = pixma_newcmd (&mp->cb, cmd_gamma, 2048 + 8, 0);
+ /* Gamma table for 2nd+ generation: 1024 * uint16_le */
+ data = pixma_newcmd (&mp->cb, cmd_gamma, 1024 * 2 + 8, 0);
data[0] = 0x10;
pixma_set_be16 (0x0804, data + 2);
if (lut)
{
- int i;
- for (i = 0; i < 1024; i++)
- {
- int j = (i << 2) + (i >> 8);
- data[4 + 2 * i + 0] = lut[j];
- data[4 + 2 * i + 1] = lut[j];
- }
+ /* PDBG (pixma_dbg (4, "*send_gamma_table***** Use 1024 * 2 bytes from LUT ***** \n")); */
+ /* PDBG (pixma_hexdump (4, lut, 1024 * 2)); */
+ memcpy (data + 4, lut, 1024 * 2);
}
else
{
- int i;
- pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 2048);
- for (i = 0; i < 1024; i++)
- {
- int j = (i << 1) + (i >> 9);
- data[4 + 2 * i + 0] = data[4 + j];
- data[4 + 2 * i + 1] = data[4 + j];
- }
+ /* fallback: we should never see this */
+ PDBG (pixma_dbg (4, "*send_gamma_table***** Generate 1024 * 2 Table with %f ***** \n",
+ s->param->gamma));
+ pixma_fill_gamma_table (s->param->gamma, data + 4, 1024);
+ /* PDBG (pixma_hexdump (4, data + 4, 1024 * 2)); */
}
}
return pixma_exec (s, &mp->cb);
@@ -631,6 +633,12 @@ calc_raw_width (const mp150_t * mp, const pixma_scan_param_t * param)
return raw_width;
}
+static int
+is_gray_16 (pixma_t * s)
+{
+ return (s->param->mode == PIXMA_SCAN_MODE_GRAY_16);
+}
+
static unsigned
get_cis_line_size (pixma_t * s)
{
@@ -640,7 +648,9 @@ get_cis_line_size (pixma_t * s)
__func__, s->param->line_size, s->param->w, s->param->wx, mp->scale));*/
return (s->param->wx ? s->param->line_size / s->param->w * s->param->wx
- : s->param->line_size) * mp->scale;
+ : s->param->line_size)
+ * mp->scale
+ * (is_gray_16(s) ? 3 : 1);
}
static int
@@ -705,10 +715,12 @@ send_scan_param (pixma_t * s)
pixma_set_be32 (y, data + 0x10);
pixma_set_be32 (wx, data + 0x14);
pixma_set_be32 (h, data + 0x18);
- data[0x1c] = (s->param->channels != 1) ? 0x08 : 0x04;
+ /*PDBG (pixma_dbg (4, "*send_scan_param gen. 3+ ***** Setting: channels=%hi depth=%hi ***** \n",
+ s->param->channels, s->param->depth));*/
+ data[0x1c] = ((s->param->channels != 1) || (is_gray_16(s)) ? 0x08 : 0x04);
data[0x1d] = ((s->param->software_lineart) ? 8 : s->param->depth)
- * s->param->channels; /* bits per pixel */
+ * (is_gray_16(s) ? 3 : s->param->channels); /* bits per pixel */
data[0x1f] = 0x01; /* This one also seen at 0. Don't know yet what's used for */
data[0x20] = 0xff;
@@ -902,7 +914,8 @@ handle_interrupt (pixma_t * s, int timeout)
|| s->cfg->pid == MX920_PID
|| s->cfg->pid == MB2300_PID
|| s->cfg->pid == MB5000_PID
- || s->cfg->pid == MB5400_PID)
+ || s->cfg->pid == MB5400_PID
+ || s->cfg->pid == TR4500_PID)
/* button no. in buf[7]
* size in buf[10] 01=A4; 02=Letter; 08=10x15; 09=13x18; 0b=auto
* format in buf[11] 01=JPEG; 02=TIFF; 03=PDF; 04=Kompakt-PDF
@@ -910,18 +923,45 @@ handle_interrupt (pixma_t * s, int timeout)
* target = format; original = size; scan-resolution = dpi */
{
if (buf[7] & 1)
- s->events = PIXMA_EV_BUTTON1 | buf[11] | buf[10]<<8 | buf[12]<<16; /* color scan */
+ {
+ /* color scan */
+ s->events = PIXMA_EV_BUTTON1 | (buf[11] & 0x0f) | (buf[10] & 0x0f) << 8
+ | (buf[12] & 0x0f) << 16;
+ }
if (buf[7] & 2)
- s->events = PIXMA_EV_BUTTON2 | buf[11] | buf[10]<<8 | buf[12]<<16; /* b/w scan */
+ {
+ /* b/w scan */
+ s->events = PIXMA_EV_BUTTON2 | (buf[11] & 0x0f) | (buf[10] & 0x0f) << 8
+ | (buf[12] & 0x0f) << 16;
+ }
+
+ /* some scanners provide additional information:
+ * document type in buf[6] 01=Document; 02=Photo; 03=Auto Scan
+ * ADF status in buf[8] 01 = ADF empty; 02 = ADF filled
+ * ADF orientation in buf[16] 01=Portrait; 02=Landscape */
+ if (s->cfg->pid == TR4500_PID)
+ {
+ s->events |= (buf[6] & 0x0f) << 12;
+ s->events |= (buf[8] & 0x0f) << 20;
+ s->events |= (buf[16] & 0x0f) << 4;
+ }
}
else if (s->cfg->pid == LIDE300_PID
|| s->cfg->pid == LIDE400_PID)
/* unknown value in buf[4]
- * target in buf[0x13]
- * always set button-1 */
+ * target in buf[0x13] 01=copy; 02=auto; 03=send; 05=start PDF; 06=finish PDF
+ * "Finish PDF" is Button-2, all others are Button-1 */
{
- if (buf[0x13])
- s->events = PIXMA_EV_BUTTON1 | buf[0x13];
+ if (buf[0x13] == 0x06)
+ {
+ /* button 2 = cancel / end scan */
+ s->events = PIXMA_EV_BUTTON2 | (buf[0x13] & 0x0f);
+ }
+ else if (buf[0x13])
+ {
+ /* button 1 = start scan */
+ s->events = PIXMA_EV_BUTTON1 | (buf[0x13] & 0x0f);
+ }
}
else
/* button no. in buf[0]
@@ -937,9 +977,15 @@ handle_interrupt (pixma_t * s, int timeout)
if (buf[9] & 2)
query_status (s);
if (buf[0] & 2)
- s->events = PIXMA_EV_BUTTON2 | buf[1] | ((buf[0] & 0xf0) << 4); /* b/w scan */
+ {
+ /* b/w scan */
+ s->events = PIXMA_EV_BUTTON2 | (buf[1] & 0x0f) | (buf[0] & 0xf0) << 4;
+ }
if (buf[0] & 1)
- s->events = PIXMA_EV_BUTTON1 | buf[1] | ((buf[0] & 0xf0) << 4); /* color scan */
+ {
+ /* color scan */
+ s->events = PIXMA_EV_BUTTON1 | (buf[1] & 0x0f) | ((buf[0] & 0xf0) << 4);
+ }
}
return 1;
}
@@ -1062,7 +1108,7 @@ post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib)
}
/* process image sizes */
- c = s->param->channels
+ c = (is_gray_16(s) ? 3 : s->param->channels)
* ((s->param->software_lineart) ? 8 : s->param->depth) / 8; /* color channels count */
cw = c * s->param->w; /* image width */
cx = c * s->param->xs; /* x-offset */
@@ -1104,7 +1150,6 @@ post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib)
* MP220, MX360 and generation 5 scanners are exceptions */
if (n > 1
&& s->cfg->pid != MP220_PID
- && s->cfg->pid != MP490_PID
&& s->cfg->pid != MX360_PID
&& (mp->generation < 5
/* generation 5 scanners *with* special image format */
@@ -1136,6 +1181,9 @@ post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib)
/* Color / Gray to Lineart convert */
if (s->param->software_lineart)
cptr = gptr = pixma_binarize_line (s->param, gptr, cptr, s->param->w, c);
+ /* Color to Grayscale convert for 16bit gray */
+ else if (is_gray_16(s))
+ cptr = gptr = pixma_rgb_to_gray (gptr, cptr, s->param->w, c);
else
cptr += cw;
}
@@ -1218,22 +1266,41 @@ mp150_check_param (pixma_t * s, pixma_scan_param_t * sp)
{
mp150_t *mp = (mp150_t *) s->subdriver;
- /* PDBG (pixma_dbg (4, "*mp150_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n",
- sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx)); */
+ /* PDBG (pixma_dbg (4, "*mp150_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u, gamma=%f *****\n",
+ sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx, sp->gamma)); */
- /* MP150 only supports 8 bit per channel in color and grayscale mode */
- if (sp->depth != 1)
- {
- sp->software_lineart = 0;
+ sp->channels = 3;
+ sp->software_lineart = 0;
+ switch (sp->mode)
+ {
+ /* standard scan modes
+ * 8 bit per channel in color and grayscale mode */
+ case PIXMA_SCAN_MODE_GRAY:
+ sp->channels = 1;
+ /* fall through */
+ case PIXMA_SCAN_MODE_COLOR:
sp->depth = 8;
- }
- else
- {
- /* software lineart */
+ break;
+ /* extended scan modes for 48 bit flatbed scanners
+ * 16 bit per channel in color and grayscale mode */
+ case PIXMA_SCAN_MODE_GRAY_16:
+ sp->channels = 1;
+ sp->depth = 16;
+ break;
+ case PIXMA_SCAN_MODE_COLOR_48:
+ sp->channels = 3;
+ sp->depth = 16;
+ break;
+ /* software lineart
+ * 1 bit per channel */
+ case PIXMA_SCAN_MODE_LINEART:
sp->software_lineart = 1;
- sp->depth = 1;
sp->channels = 1;
- }
+ sp->depth = 1;
+ break;
+ default:
+ break;
+ }
/* for software lineart w must be a multiple of 8 */
if (sp->software_lineart == 1 && sp->w % 8)
@@ -1596,6 +1663,7 @@ static const pixma_scan_ops_t pixma_mp150_ops = {
0, /* iface */ \
&pixma_mp150_ops, /* ops */ \
min_dpi, /* min_xdpi */ \
+ 0, /* min_xdpi_16 not used in this subdriver */ \
dpi, 2*(dpi), /* xdpi, ydpi */ \
adftpu_min_dpi, adftpu_max_dpi, /* adftpu_min_dpi, adftpu_max_dpi */ \
0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \
@@ -1610,11 +1678,11 @@ static const pixma_scan_ops_t pixma_mp150_ops = {
const pixma_config_t pixma_mp150_devices[] = {
/* Generation 1: CIS */
- DEVICE ("Canon PIXMA MP150", "MP150", MP150_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
- DEVICE ("Canon PIXMA MP170", "MP170", MP170_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
- DEVICE ("Canon PIXMA MP450", "MP450", MP450_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
- DEVICE ("Canon PIXMA MP500", "MP500", MP500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
- DEVICE ("Canon PIXMA MP530", "MP530", MP530_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF),
+ DEVICE ("Canon PIXMA MP150", "MP150", MP150_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_GT_4096),
+ DEVICE ("Canon PIXMA MP170", "MP170", MP170_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_GT_4096),
+ DEVICE ("Canon PIXMA MP450", "MP450", MP450_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_GT_4096),
+ DEVICE ("Canon PIXMA MP500", "MP500", MP500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_GT_4096),
+ DEVICE ("Canon PIXMA MP530", "MP530", MP530_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_GT_4096 | PIXMA_CAP_ADF),
/* Generation 2: CIS */
DEVICE ("Canon PIXMA MP140", "MP140", MP140_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS),
@@ -1675,7 +1743,7 @@ const pixma_config_t pixma_mp150_devices[] = {
/* Latest devices (2010) Generation 4 CIS */
DEVICE ("Canon PIXMA MP280", "MP280", MP280_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), /* TODO: 1200dpi doesn't work yet */
- DEVICE ("Canon PIXMA MP495", "MP495", MP495_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
+ DEVICE ("Canon PIXMA MP495", "MP495", MP495_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), /* ToDo: max. scan resolution = 1200x600dpi */
DEVICE ("Canon PIXMA MG5100", "MG5100", MG5100_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
DEVICE ("Canon PIXMA MG5200", "MG5200", MG5200_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS),
DEVICE ("Canon PIXMA MG6100", "MG6100", MG6100_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS),
@@ -1765,12 +1833,12 @@ const pixma_config_t pixma_mp150_devices[] = {
/* Latest devices (2018) Generation 5 CIS */
DEVICE ("Canon MAXIFY MB5400 Series", "MB5400", MB5400_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP | PIXMA_CAP_ADF_JPEG),
- DEVICE ("Canon MAXIFY MB5100 Series", "MB5100", MB5100_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP),
+ DEVICE ("Canon MAXIFY MB5100 Series", "MB5100", MB5100_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP | PIXMA_CAP_ADF_JPEG),
DEVICE ("Canon PIXMA TS9100 Series", "TS9100", TS9100_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS),
- DEVICE ("Canon PIXMA TR8500 Series", "TR8500", TR8500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF),
+ DEVICE ("Canon PIXMA TR8500 Series", "TR8500", TR8500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF | PIXMA_CAP_ADF_JPEG),
DEVICE ("Canon PIXMA TR7500 Series", "TR7500", TR7500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF),
DEVICE ("Canon PIXMA TS9500 Series", "TS9500", TS9500_PID, 0, 1200, 0, 600, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF),
- DEVICE ("CanoScan LiDE 400", "LIDE400", LIDE400_PID, 300, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS),
+ DEVICE ("CanoScan LiDE 400", "LIDE400", LIDE400_PID, 300, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_48BIT),
DEVICE ("CanoScan LiDE 300", "LIDE300", LIDE300_PID, 300, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS),
/* Latest devices (2019) Generation 5 CIS */
@@ -1788,7 +1856,7 @@ const pixma_config_t pixma_mp150_devices[] = {
DEVICE ("Canon PIXMA TR7530 Series", "TR7530", TR7530_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF),
DEVICE ("Canon PIXUS XK50 Series", "XK50", XK50_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
DEVICE ("Canon PIXUS XK70 Series", "XK70", XK70_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
- DEVICE ("Canon PIXMA TR4500 Series", "TR4500", TR4500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF),
+ DEVICE ("Canon PIXMA TR4500 Series", "TR4500", TR4500_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF | PIXMA_CAP_ADF_JPEG), /* ToDo: max. scan resolution = 600x1200dpi */
DEVICE ("Canon PIXMA E4200 Series", "E4200", E4200_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF),
DEVICE ("Canon PIXMA TS6200 Series", "TS6200", TS6200_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
DEVICE ("Canon PIXMA TS6280 Series", "TS6280", TS6280_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
@@ -1798,8 +1866,10 @@ const pixma_config_t pixma_mp150_devices[] = {
DEVICE ("Canon PIXMA TS8230 Series", "TS8230", TS8230_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
DEVICE ("Canon PIXMA TS9580 Series", "TS9580", TS9580_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF),
DEVICE ("Canon PIXMA TR9530 Series", "TR9530", TR9530_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF),
+ DEVICE ("Canon PIXMA G7000 Series", "G7000", G7000_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), /* ToDo: ADF has legal paper length */
DEVICE ("Canon PIXMA G6000 Series", "G6000", G6000_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS),
DEVICE ("Canon PIXMA G6080 Series", "G6080", G6080_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS),
+ DEVICE ("Canon PIXMA GM4000 Series", "GM4000", GM4000_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), /* ToDo: ADF has legal paper length */
DEVICE ("Canon PIXUS XK80 Series", "XK80", XK80_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
DEVICE ("Canon PIXMA TS5300 Series", "TS5300", TS5300_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
DEVICE ("Canon PIXMA TS5380 Series", "TS5380", TS5380_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS),
diff --git a/backend/pixma/pixma_mp730.c b/backend/pixma/pixma_mp730.c
index 93d518b..fcc9ae8 100644
--- a/backend/pixma/pixma_mp730.c
+++ b/backend/pixma/pixma_mp730.c
@@ -1,6 +1,6 @@
/* SANE - Scanner Access Now Easy.
- Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de>
+ Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de>
Copyright (C) 2007-2008 Nicolas Martin, <nicols-guest at alioth dot debian dot org>
Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
@@ -815,7 +815,7 @@ static const pixma_scan_ops_t pixma_mp730_ops = {
0x04a9, pid, /* vid pid */ \
1, /* iface */ \
&pixma_mp730_ops, /* ops */ \
- 0, /* min_xdpi not used in this subdriver */ \
+ 0, 0, /* min_xdpi & min_xdpi_16 not used in this subdriver */ \
dpi, dpi, /* xdpi, ydpi */ \
0, 0, /* adftpu_min_dpi & adftpu_max_dpi not used in this subdriver */ \
0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \
diff --git a/backend/pixma/pixma_mp750.c b/backend/pixma/pixma_mp750.c
index 7f00023..cc1c3ad 100644
--- a/backend/pixma/pixma_mp750.c
+++ b/backend/pixma/pixma_mp750.c
@@ -1,6 +1,6 @@
/* SANE - Scanner Access Now Easy.
- Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de>
+ Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de>
Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
This file is part of the SANE package.
@@ -955,7 +955,7 @@ static const pixma_scan_ops_t pixma_mp750_ops = {
0x04a9, pid, /* vid pid */ \
0, /* iface */ \
&pixma_mp750_ops, /* ops */ \
- 0, /* min_xdpi not used in this subdriver */ \
+ 0, 0, /* min_xdpi & min_xdpi_16 not used in this subdriver */ \
dpi, 2*(dpi), /* xdpi, ydpi */ \
0, 0, /* adftpu_min_dpi & adftpu_max_dpi not used in this subdriver */ \
0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \
diff --git a/backend/pixma/pixma_mp800.c b/backend/pixma/pixma_mp800.c
index feef611..905c246 100644
--- a/backend/pixma/pixma_mp800.c
+++ b/backend/pixma/pixma_mp800.c
@@ -1,6 +1,6 @@
/* SANE - Scanner Access Now Easy.
- Copyright (C) 2011-2019 Rolf Bensch <rolf at bensch hyphen online dot de>
+ Copyright (C) 2011-2020 Rolf Bensch <rolf at bensch hyphen online dot de>
Copyright (C) 2007-2009 Nicolas Martin, <nicols-guest at alioth dot debian dot org>
Copyright (C) 2006-2007 Wittawat Yamwong <wittawat@web.de>
@@ -91,7 +91,6 @@
4096 = size of gamma table. 24 = header + checksum */
#define IMAGE_BLOCK_SIZE (512*1024)
#define CMDBUF_SIZE (4096 + 24)
-#define DEFAULT_GAMMA 2.0 /***** Gamma different from 1.0 is potentially impacting color profile generation *****/
#define UNKNOWN_PID 0xffff
#define CANON_VID 0x04a9
@@ -153,8 +152,6 @@
<ivec:param_set servicetype=\"scan\"><ivec:jobID>00000001</ivec:jobID>\
</ivec:param_set></ivec:contents></cmd>"
-#define XML_OK "<ivec:response>OK</ivec:response>"
-
enum mp810_state_t
{
state_idle,
@@ -294,7 +291,7 @@ static int send_xml_dialog (pixma_t * s, const char * xml_message)
PDBG(pixma_dbg (10, "XML message sent to scanner:\n%s\n", xml_message));
PDBG(pixma_dbg (10, "XML response back from scanner:\n%s\n", mp->cb.buf));
- return (strcasestr ((const char *) mp->cb.buf, XML_OK) != NULL);
+ return pixma_parse_xml_response((const char*)mp->cb.buf) == PIXMA_STATUS_OK;
}
static void new_cmd_tpu_msg (pixma_t *s, pixma_cmdbuf_t * cb, uint16_t cmd)
@@ -438,44 +435,47 @@ static int send_gamma_table (pixma_t * s)
const uint8_t *lut = s->param->gamma_table;
uint8_t *data;
- if (mp->generation == 1)
+ if (s->cfg->cap & PIXMA_CAP_GT_4096)
{
data = pixma_newcmd (&mp->cb, cmd_gamma, 4096 + 8, 0);
data[0] = (s->param->channels == 3) ? 0x10 : 0x01;
pixma_set_be16 (0x1004, data + 2);
if (lut)
- memcpy (data + 4, lut, 4096);
- else
- pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 4096);
- }
- else
- {
- /* FIXME: Gamma table for 2nd generation: 1024 * uint16_le */
- data = pixma_newcmd (&mp->cb, cmd_gamma, 2048 + 8, 0);
- data[0] = 0x10;
- pixma_set_be16 (0x0804, data + 2);
- if (lut)
- {
- int i;
- for (i = 0; i < 1024; i++)
{
- int j = (i << 2) + (i >> 8);
- data[4 + 2 * i + 0] = lut[j];
- data[4 + 2 * i + 1] = lut[j];
+ /* PDBG (pixma_dbg (4, "*send_gamma_table***** Use 4096 bytes from LUT ***** \n")); */
+ /* PDBG (pixma_hexdump (4, lut, 4096)); */
+ memcpy (data + 4, lut, 4096);
}
- }
else
- {
- int i;
- pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 2048);
- for (i = 0; i < 1024; i++)
{
- int j = (i << 1) + (i >> 9);
- data[4 + 2 * i + 0] = data[4 + j];
- data[4 + 2 * i + 1] = data[4 + j];
+ /* fallback: we should never see this */
+ PDBG (pixma_dbg (4, "*send_gamma_table***** Generate 4096 bytes Table with %f ***** \n",
+ s->param->gamma));
+ pixma_fill_gamma_table (s->param->gamma, data + 4, 4096);
+ /* PDBG (pixma_hexdump (4, data + 4, 4096)); */
}
- }
}
+ else
+ {
+ /* Gamma table for 2nd+ generation: 1024 * uint16_le */
+ data = pixma_newcmd (&mp->cb, cmd_gamma, 1024 * 2 + 8, 0);
+ data[0] = 0x10;
+ pixma_set_be16 (0x0804, data + 2);
+ if (lut)
+ {
+ /* PDBG (pixma_dbg (4, "*send_gamma_table***** Use 1024 * 2 bytes from LUT ***** \n")); */
+ /* PDBG (pixma_hexdump (4, lut, 1024 * 2)); */
+ memcpy (data + 4, lut, 1024 * 2);
+ }
+ else
+ {
+ /* fallback: we should never see this */
+ PDBG (pixma_dbg (4, "*send_gamma_table***** Generate 1024 * 2 bytes Table with %f ***** \n",
+ s->param->gamma));
+ pixma_fill_gamma_table (s->param->gamma, data + 4, 1024);
+ /* PDBG (pixma_hexdump (4, data + 4, 1024 * 2)); */
+ }
+ }
return pixma_exec (s, &mp->cb);
}
@@ -1172,9 +1172,17 @@ static int handle_interrupt (pixma_t * s, int timeout)
* target = format; original = size; scan-resolution = dpi */
{
if (buf[7] & 1)
- s->events = PIXMA_EV_BUTTON1 | buf[11] | buf[10]<<8 | buf[12]<<16; /* color scan */
+ {
+ /* color scan */
+ s->events = PIXMA_EV_BUTTON1 | (buf[11] & 0x0f) | (buf[10] & 0x0f) << 8
+ | (buf[12] & 0x0f) << 16;
+ }
if (buf[7] & 2)
- s->events = PIXMA_EV_BUTTON2 | buf[11] | buf[10]<<8 | buf[12]<<16; /* b/w scan */
+ {
+ /* b/w scan */
+ s->events = PIXMA_EV_BUTTON2 | (buf[11] & 0x0f) | (buf[10] & 0x0f) << 8
+ | (buf[12] & 0x0f) << 16;
+ }
}
else if (s->cfg->pid == CS8800F_PID
|| s->cfg->pid == CS9000F_PID
@@ -1185,9 +1193,15 @@ static int handle_interrupt (pixma_t * s, int timeout)
{
if ((s->cfg->pid == CS8800F_PID && buf[1] == 0x70)
|| (s->cfg->pid != CS8800F_PID && buf[1] == 0x50))
- s->events = PIXMA_EV_BUTTON2 | buf[1] >> 4; /* button 2 = cancel / end scan */
+ {
+ /* button 2 = cancel / end scan */
+ s->events = PIXMA_EV_BUTTON2 | buf[1] >> 4;
+ }
else
- s->events = PIXMA_EV_BUTTON1 | buf[1] >> 4; /* button 1 = start scan */
+ {
+ /* button 1 = start scan */
+ s->events = PIXMA_EV_BUTTON1 | buf[1] >> 4;
+ }
}
else
/* button no. in buf[0]
@@ -1204,9 +1218,15 @@ static int handle_interrupt (pixma_t * s, int timeout)
query_status (s);
if (buf[0] & 2)
- s->events = PIXMA_EV_BUTTON2 | buf[1] | ((buf[0] & 0xf0) << 4); /* b/w scan */
+ {
+ /* b/w scan */
+ s->events = PIXMA_EV_BUTTON2 | (buf[1] & 0x0f) | (buf[0] & 0xf0) << 4;
+ }
if (buf[0] & 1)
- s->events = PIXMA_EV_BUTTON1 | buf[1] | ((buf[0] & 0xf0) << 4); /* color scan */
+ {
+ /* color scan */
+ s->events = PIXMA_EV_BUTTON1 | (buf[1] & 0x0f) | (buf[0] & 0xf0) << 4;
+ }
}
return 1;
}
@@ -1871,8 +1891,8 @@ static int mp810_check_param (pixma_t * s, pixma_scan_param_t * sp)
mp810_t *mp = (mp810_t *) s->subdriver;
unsigned w_max;
- /* PDBG (pixma_dbg (4, "*mp810_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n",
- sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx)); */
+ /* PDBG (pixma_dbg (4, "*mp810_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u, gamma=%f *****\n",
+ sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx, sp->gamma)); */
sp->channels = 3;
sp->software_lineart = 0;
@@ -2066,9 +2086,7 @@ static int mp810_check_param (pixma_t * s, pixma_scan_param_t * sp)
k = MAX (sp->xdpi, 300) / sp->xdpi;
else if (sp->source == PIXMA_SOURCE_TPU
|| sp->mode == PIXMA_SCAN_MODE_COLOR_48 || sp->mode == PIXMA_SCAN_MODE_GRAY_16)
- /* TPU mode and 16 bit flatbed scans
- * TODO: either the frontend (xsane) cannot handle 48 bit flatbed scans @ 75 dpi (prescan)
- * or there is a bug in this subdriver */
+ /* TPU mode and 16 bit flatbed scans */
k = MAX (sp->xdpi, 150) / sp->xdpi;
else
/* default */
@@ -2375,13 +2393,14 @@ static const pixma_scan_ops_t pixma_mp800_ops =
mp810_get_status
};
-#define DEVICE(name, model, pid, dpi, adftpu_min_dpi, adftpu_max_dpi, tpuir_min_dpi, tpuir_max_dpi, w, h, cap) { \
+#define DEVICE(name, model, pid, min_dpi_16, dpi, adftpu_min_dpi, adftpu_max_dpi, tpuir_min_dpi, tpuir_max_dpi, w, h, cap) { \
name, /* name */ \
model, /* model */ \
CANON_VID, pid, /* vid pid */ \
0, /* iface */ \
&pixma_mp800_ops, /* ops */ \
0, /* min_xdpi not used in this subdriver */ \
+ min_dpi_16, /* min_xdpi_16 */ \
dpi, 2*(dpi), /* xdpi, ydpi */ \
adftpu_min_dpi, adftpu_max_dpi, /* adftpu_min_dpi, adftpu_max_dpi */ \
tpuir_min_dpi, tpuir_max_dpi, /* tpuir_min_dpi, tpuir_max_dpi */ \
@@ -2393,42 +2412,42 @@ static const pixma_scan_ops_t pixma_mp800_ops =
PIXMA_CAP_GAMMA_TABLE|PIXMA_CAP_EVENTS|cap \
}
-#define END_OF_DEVICE_LIST DEVICE(NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+#define END_OF_DEVICE_LIST DEVICE(NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
const pixma_config_t pixma_mp800_devices[] =
{
/* Generation 1: CCD */
- DEVICE ("Canon PIXMA MP800", "MP800", MP800_PID, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
- DEVICE ("Canon PIXMA MP800R", "MP800R", MP800R_PID, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
- DEVICE ("Canon PIXMA MP830", "MP830", MP830_PID, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_ADFDUP),
+ DEVICE ("Canon PIXMA MP800", "MP800", MP800_PID, 0, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_TPU | PIXMA_CAP_GT_4096),
+ DEVICE ("Canon PIXMA MP800R", "MP800R", MP800R_PID, 0, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_TPU | PIXMA_CAP_GT_4096),
+ DEVICE ("Canon PIXMA MP830", "MP830", MP830_PID, 0, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_ADFDUP | PIXMA_CAP_GT_4096),
/* Generation 2: CCD */
- DEVICE ("Canon PIXMA MP810", "MP810", MP810_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
- DEVICE ("Canon PIXMA MP960", "MP960", MP960_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
+ DEVICE ("Canon PIXMA MP810", "MP810", MP810_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
+ DEVICE ("Canon PIXMA MP960", "MP960", MP960_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
/* Generation 3 CCD not managed as Generation 2 */
- DEVICE ("Canon Pixma MP970", "MP970", MP970_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
+ DEVICE ("Canon Pixma MP970", "MP970", MP970_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
/* Flatbed scanner CCD (2007) */
- DEVICE ("Canoscan 8800F", "8800F", CS8800F_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU /*| PIXMA_CAP_NEGATIVE*/ | PIXMA_CAP_48BIT),
+ DEVICE ("Canoscan 8800F", "8800F", CS8800F_PID, 150, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU /*| PIXMA_CAP_NEGATIVE*/ | PIXMA_CAP_48BIT),
/* PIXMA 2008 vintage CCD */
- DEVICE ("Canon MP980 series", "MP980", MP980_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
+ DEVICE ("Canon MP980 series", "MP980", MP980_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
/* Generation 4 CCD */
- DEVICE ("Canon MP990 series", "MP990", MP990_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
+ DEVICE ("Canon MP990 series", "MP990", MP990_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
/* Flatbed scanner (2010) */
- DEVICE ("Canoscan 9000F", "9000F", CS9000F_PID, 4800, 300, 9600, 600, 2400, 638, 877, PIXMA_CAP_TPUIR /*| PIXMA_CAP_NEGATIVE*/ | PIXMA_CAP_48BIT),
+ DEVICE ("Canoscan 9000F", "9000F", CS9000F_PID, 150, 4800, 300, 9600, 600, 2400, 638, 877, PIXMA_CAP_TPUIR /*| PIXMA_CAP_NEGATIVE*/ | PIXMA_CAP_48BIT),
/* Latest devices (2010) Generation 4 CCD untested */
- DEVICE ("Canon PIXMA MG8100", "MG8100", MG8100_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
+ DEVICE ("Canon PIXMA MG8100", "MG8100", MG8100_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
/* Latest devices (2011) Generation 4 CCD untested */
- DEVICE ("Canon PIXMA MG8200", "MG8200", MG8200_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
+ DEVICE ("Canon PIXMA MG8200", "MG8200", MG8200_PID, 0, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU),
/* Flatbed scanner (2013) */
- DEVICE ("Canoscan 9000F Mark II", "9000FMarkII", CS9000F_MII_PID, 4800, 300, 9600, 600, 2400, 638, 877, PIXMA_CAP_TPUIR | PIXMA_CAP_48BIT),
+ DEVICE ("Canoscan 9000F Mark II", "9000FMarkII", CS9000F_MII_PID, 150, 4800, 300, 9600, 600, 2400, 638, 877, PIXMA_CAP_TPUIR | PIXMA_CAP_48BIT),
END_OF_DEVICE_LIST
};
diff --git a/backend/pixma/pixma_sane_options.c b/backend/pixma/pixma_sane_options.c
deleted file mode 100644
index 2b8f609..0000000
--- a/backend/pixma/pixma_sane_options.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/* Automatically generated from pixma_sane.c */
-static const SANE_Range constraint_gamma_table =
- { 0,255,0 };
-static const SANE_Range constraint_gamma =
- { SANE_FIX(0.3),SANE_FIX(5),SANE_FIX(0) };
-static const SANE_Range constraint_threshold =
- { 0,100,1 };
-static const SANE_Range constraint_threshold_curve =
- { 0,127,1 };
-static const SANE_Range constraint_adf_wait =
- { 0,3600,1 };
-
-
-static
-int find_string_in_list(SANE_String_Const str, const SANE_String_Const *list)
-{
- int i;
- for (i = 0; list[i] && strcmp(str, list[i]) != 0; i++) {}
- return i;
-}
-
-static
-int build_option_descriptors(struct pixma_sane_t *ss)
-{
- SANE_Option_Descriptor *sod;
- option_descriptor_t *opt;
-
- memset(OPT_IN_CTX, 0, sizeof(OPT_IN_CTX));
-
- opt = &(OPT_IN_CTX[opt_opt_num_opts]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_INT;
- sod->title = SANE_TITLE_NUM_OPTIONS;
- sod->desc = SANE_DESC_NUM_OPTIONS;
- sod->name = "";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_DETECT;
- sod->constraint_type = SANE_CONSTRAINT_NONE;
- OPT_IN_CTX[opt_opt_num_opts].info = 0;
- opt->def.w = opt_last;
- opt->val.w = opt_last;
-
- opt = &(OPT_IN_CTX[opt__group_1]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_GROUP;
- sod->title = SANE_I18N("Scan mode");
- sod->desc = sod->title;
-
- opt = &(OPT_IN_CTX[opt_resolution]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_INT;
- sod->title = SANE_TITLE_SCAN_RESOLUTION;
- sod->desc = SANE_DESC_SCAN_RESOLUTION;
- sod->name = "resolution";
- sod->unit = SANE_UNIT_DPI;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC;
- sod->constraint_type = SANE_CONSTRAINT_WORD_LIST;
- sod->constraint.word_list = ss->dpi_list;
- OPT_IN_CTX[opt_resolution].info = SANE_INFO_RELOAD_PARAMS;
- opt->def.w = 75;
- opt->val.w = 75;
-
- opt = &(OPT_IN_CTX[opt_mode]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_STRING;
- sod->title = SANE_TITLE_SCAN_MODE;
- sod->desc = SANE_DESC_SCAN_MODE;
- sod->name = "mode";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 31;
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC;
- sod->constraint_type = SANE_CONSTRAINT_STRING_LIST;
- sod->constraint.string_list = ss->mode_list;
- OPT_IN_CTX[opt_mode].info = SANE_INFO_RELOAD_PARAMS;
- opt->def.s = SANE_VALUE_SCAN_MODE_COLOR;
- opt->val.w = find_string_in_list(opt->def.s, sod->constraint.string_list);
-
- opt = &(OPT_IN_CTX[opt_source]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_STRING;
- sod->title = SANE_TITLE_SCAN_SOURCE;
- sod->desc = SANE_I18N("Selects the scan source (such as a document-feeder). Set source before mode and resolution. Resets mode and resolution to auto values.");
- sod->name = "source";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 31;
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT;
- sod->constraint_type = SANE_CONSTRAINT_STRING_LIST;
- sod->constraint.string_list = ss->source_list;
- OPT_IN_CTX[opt_source].info = 0;
- opt->def.s = SANE_I18N("Flatbed");
- opt->val.w = find_string_in_list(opt->def.s, sod->constraint.string_list);
-
- opt = &(OPT_IN_CTX[opt_button_controlled]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_BOOL;
- sod->title = SANE_I18N("Button-controlled scan");
- sod->desc = SANE_I18N("When enabled, scan process will not start immediately. To proceed, press \"SCAN\" button (for MP150) or \"COLOR\" button (for other models). To cancel, press \"GRAY\" button.");
- sod->name = "button-controlled";
- sod->unit = SANE_UNIT_NONE;
- sod->size = sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_INACTIVE;
- sod->constraint_type = SANE_CONSTRAINT_NONE;
- OPT_IN_CTX[opt_button_controlled].info = 0;
- opt->def.w = SANE_FALSE;
- opt->val.w = SANE_FALSE;
-
- opt = &(OPT_IN_CTX[opt__group_2]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_GROUP;
- sod->title = SANE_I18N("Gamma");
- sod->desc = sod->title;
-
- opt = &(OPT_IN_CTX[opt_custom_gamma]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_BOOL;
- sod->title = SANE_TITLE_CUSTOM_GAMMA;
- sod->desc = SANE_DESC_CUSTOM_GAMMA;
- sod->name = "custom-gamma";
- sod->unit = SANE_UNIT_NONE;
- sod->size = sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE;
- sod->constraint_type = SANE_CONSTRAINT_NONE;
- OPT_IN_CTX[opt_custom_gamma].info = 0;
- opt->def.w = SANE_TRUE;
- opt->val.w = SANE_TRUE;
-
- opt = &(OPT_IN_CTX[opt_gamma_table]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_INT;
- sod->title = SANE_TITLE_GAMMA_VECTOR;
- sod->desc = SANE_DESC_GAMMA_VECTOR;
- sod->name = "gamma-table";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 4096 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE;
- sod->constraint_type = SANE_CONSTRAINT_RANGE;
- sod->constraint.range = &constraint_gamma_table;
- OPT_IN_CTX[opt_gamma_table].info = 0;
-
- opt = &(OPT_IN_CTX[opt_gamma]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_FIXED;
- sod->title = SANE_I18N("Gamma function exponent");
- sod->desc = SANE_I18N("Changes intensity of midtones");
- sod->name = "gamma";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE;
- sod->constraint_type = SANE_CONSTRAINT_RANGE;
- sod->constraint.range = &constraint_gamma;
- OPT_IN_CTX[opt_gamma].info = 0;
- opt->def.w = SANE_FIX(AUTO_GAMMA);
- opt->val.w = SANE_FIX(AUTO_GAMMA);
-
- opt = &(OPT_IN_CTX[opt__group_3]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_GROUP;
- sod->title = SANE_I18N("Geometry");
- sod->desc = sod->title;
-
- opt = &(OPT_IN_CTX[opt_tl_x]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_FIXED;
- sod->title = SANE_TITLE_SCAN_TL_X;
- sod->desc = SANE_DESC_SCAN_TL_X;
- sod->name = "tl-x";
- sod->unit = SANE_UNIT_MM;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC;
- sod->constraint_type = SANE_CONSTRAINT_RANGE;
- sod->constraint.range = &ss->xrange;
- OPT_IN_CTX[opt_tl_x].info = SANE_INFO_RELOAD_PARAMS;
- opt->def.w = SANE_FIX(0);
- opt->val.w = SANE_FIX(0);
-
- opt = &(OPT_IN_CTX[opt_tl_y]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_FIXED;
- sod->title = SANE_TITLE_SCAN_TL_Y;
- sod->desc = SANE_DESC_SCAN_TL_Y;
- sod->name = "tl-y";
- sod->unit = SANE_UNIT_MM;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC;
- sod->constraint_type = SANE_CONSTRAINT_RANGE;
- sod->constraint.range = &ss->yrange;
- OPT_IN_CTX[opt_tl_y].info = SANE_INFO_RELOAD_PARAMS;
- opt->def.w = SANE_FIX(0);
- opt->val.w = SANE_FIX(0);
-
- opt = &(OPT_IN_CTX[opt_br_x]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_FIXED;
- sod->title = SANE_TITLE_SCAN_BR_X;
- sod->desc = SANE_DESC_SCAN_BR_X;
- sod->name = "br-x";
- sod->unit = SANE_UNIT_MM;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC;
- sod->constraint_type = SANE_CONSTRAINT_RANGE;
- sod->constraint.range = &ss->xrange;
- OPT_IN_CTX[opt_br_x].info = SANE_INFO_RELOAD_PARAMS;
- opt->def.w = sod->constraint.range->max;
- opt->val.w = sod->constraint.range->max;
-
- opt = &(OPT_IN_CTX[opt_br_y]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_FIXED;
- sod->title = SANE_TITLE_SCAN_BR_Y;
- sod->desc = SANE_DESC_SCAN_BR_Y;
- sod->name = "br-y";
- sod->unit = SANE_UNIT_MM;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC;
- sod->constraint_type = SANE_CONSTRAINT_RANGE;
- sod->constraint.range = &ss->yrange;
- OPT_IN_CTX[opt_br_y].info = SANE_INFO_RELOAD_PARAMS;
- opt->def.w = sod->constraint.range->max;
- opt->val.w = sod->constraint.range->max;
-
- opt = &(OPT_IN_CTX[opt__group_4]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_GROUP;
- sod->title = SANE_I18N("Buttons");
- sod->desc = sod->title;
-
- opt = &(OPT_IN_CTX[opt_button_update]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_BUTTON;
- sod->title = SANE_I18N("Update button state");
- sod->desc = sod->title;
- sod->name = "button-update";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 0;
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED;
- sod->constraint_type = SANE_CONSTRAINT_NONE;
- OPT_IN_CTX[opt_button_update].info = 0;
-
- opt = &(OPT_IN_CTX[opt_button_1]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_INT;
- sod->title = SANE_I18N("Button 1");
- sod->desc = sod->title;
- sod->name = "button-1";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED;
- sod->constraint_type = SANE_CONSTRAINT_NONE;
- OPT_IN_CTX[opt_button_1].info = 0;
- opt->def.w = 0;
- opt->val.w = 0;
-
- opt = &(OPT_IN_CTX[opt_button_2]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_INT;
- sod->title = SANE_I18N("Button 2");
- sod->desc = sod->title;
- sod->name = "button-2";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED;
- sod->constraint_type = SANE_CONSTRAINT_NONE;
- OPT_IN_CTX[opt_button_2].info = 0;
- opt->def.w = 0;
- opt->val.w = 0;
-
- opt = &(OPT_IN_CTX[opt_original]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_INT;
- sod->title = SANE_I18N("Type of original to scan");
- sod->desc = sod->title;
- sod->name = "original";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED;
- sod->constraint_type = SANE_CONSTRAINT_NONE;
- OPT_IN_CTX[opt_original].info = 0;
- opt->def.w = 0;
- opt->val.w = 0;
-
- opt = &(OPT_IN_CTX[opt_target]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_INT;
- sod->title = SANE_I18N("Target operation type");
- sod->desc = sod->title;
- sod->name = "target";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED;
- sod->constraint_type = SANE_CONSTRAINT_NONE;
- OPT_IN_CTX[opt_target].info = 0;
- opt->def.w = 0;
- opt->val.w = 0;
-
- opt = &(OPT_IN_CTX[opt_scan_resolution]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_INT;
- sod->title = SANE_I18N("Scan resolution");
- sod->desc = sod->title;
- sod->name = "scan-resolution";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED;
- sod->constraint_type = SANE_CONSTRAINT_NONE;
- OPT_IN_CTX[opt_scan_resolution].info = 0;
- opt->def.w = 0;
- opt->val.w = 0;
-
- opt = &(OPT_IN_CTX[opt__group_5]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_GROUP;
- sod->title = SANE_I18N("Extras");
- sod->desc = sod->title;
-
- opt = &(OPT_IN_CTX[opt_threshold]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_INT;
- sod->title = SANE_TITLE_THRESHOLD;
- sod->desc = SANE_DESC_THRESHOLD;
- sod->name = "threshold";
- sod->unit = SANE_UNIT_PERCENT;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE;
- sod->constraint_type = SANE_CONSTRAINT_RANGE;
- sod->constraint.range = &constraint_threshold;
- OPT_IN_CTX[opt_threshold].info = 0;
- opt->def.w = 50;
- opt->val.w = 50;
-
- opt = &(OPT_IN_CTX[opt_threshold_curve]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_INT;
- sod->title = SANE_I18N("Threshold curve");
- sod->desc = SANE_I18N("Dynamic threshold curve, from light to dark, normally 50-65");
- sod->name = "threshold-curve";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE;
- sod->constraint_type = SANE_CONSTRAINT_RANGE;
- sod->constraint.range = &constraint_threshold_curve;
- OPT_IN_CTX[opt_threshold_curve].info = 0;
-
- opt = &(OPT_IN_CTX[opt_adf_wait]);
- sod = &opt->sod;
- sod->type = SANE_TYPE_INT;
- sod->title = SANE_I18N("ADF Waiting Time");
- sod->desc = SANE_I18N("When set, the scanner waits upto the specified time in seconds for a new document inserted into the automatic document feeder.");
- sod->name = "adf-wait";
- sod->unit = SANE_UNIT_NONE;
- sod->size = 1 * sizeof(SANE_Word);
- sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE;
- sod->constraint_type = SANE_CONSTRAINT_RANGE;
- sod->constraint.range = &constraint_adf_wait;
- OPT_IN_CTX[opt_adf_wait].info = 0;
- opt->def.w = 0;
- opt->val.w = 0;
-
- return 0;
-
-}
diff --git a/backend/pixma/pixma_sane_options.h b/backend/pixma/pixma_sane_options.h
deleted file mode 100644
index 1472f1f..0000000
--- a/backend/pixma/pixma_sane_options.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Automatically generated from pixma_sane.c */
-
-typedef union {
- SANE_Word w;
- SANE_Int i;
- SANE_Bool b;
- SANE_Fixed f;
- SANE_String s;
- void *ptr;
-} option_value_t;
-
-typedef enum {
- opt_opt_num_opts,
- opt__group_1,
- opt_resolution,
- opt_mode,
- opt_source,
- opt_button_controlled,
- opt__group_2,
- opt_custom_gamma,
- opt_gamma_table,
- opt_gamma,
- opt__group_3,
- opt_tl_x,
- opt_tl_y,
- opt_br_x,
- opt_br_y,
- opt__group_4,
- opt_button_update,
- opt_button_1,
- opt_button_2,
- opt_original,
- opt_target,
- opt_scan_resolution,
- opt__group_5,
- opt_threshold,
- opt_threshold_curve,
- opt_adf_wait,
- opt_last
-} option_t;
-
-
-typedef struct {
- SANE_Option_Descriptor sod;
- option_value_t val,def;
- SANE_Word info;
-} option_descriptor_t;
-
-
-struct pixma_sane_t;
-static int build_option_descriptors(struct pixma_sane_t *ss);
diff --git a/backend/pixma/scripts/pixma_gen_options.py b/backend/pixma/scripts/pixma_gen_options.py
index c4c75e0..cee2c58 100755
--- a/backend/pixma/scripts/pixma_gen_options.py
+++ b/backend/pixma/scripts/pixma_gen_options.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
+from __future__ import print_function
import sys,os,re
+import functools
class Error(Exception):
pass
@@ -181,40 +183,35 @@ def parseFile(f):
def genHeader(options):
- print """
-typedef union {
- SANE_Word w;
- SANE_Int i;
- SANE_Bool b;
- SANE_Fixed f;
- SANE_String s;
- void *ptr;
-} option_value_t;
-"""
- print 'typedef enum {'
+ print ("\ntypedef union {")
+ print (" SANE_Word w;")
+ print (" SANE_Int i;")
+ print (" SANE_Bool b;")
+ print (" SANE_Fixed f;")
+ print (" SANE_String s;")
+ print (" void *ptr;")
+ print ("} option_value_t;")
+ print ("\ntypedef enum {")
for o in options:
- print ' %(cname_opt)s,' % o
- print ' ' + opt_prefix + 'last'
- print '} option_t;'
- print """
+ print (" %(cname_opt)s," % o)
+ print (" " + opt_prefix + "last")
+ print ("} option_t;")
-typedef struct {
- SANE_Option_Descriptor sod;
- option_value_t val,def;
- SANE_Word info;
-} option_descriptor_t;
+ print ("\ntypedef struct {")
+ print (" SANE_Option_Descriptor sod;")
+ print (" option_value_t val,def;")
+ print (" SANE_Word info;")
+ print ("} option_descriptor_t;")
-
-struct pixma_sane_t;
-static int build_option_descriptors(struct pixma_sane_t *ss);
-"""
+ print ("\nstruct pixma_sane_t;")
+ print ("static int build_option_descriptors(struct pixma_sane_t *ss);\n")
def genMinMaxRange(n, t, r):
if t == 'SANE_TYPE_FIXED':
r = ['SANE_FIX(%s)' % x for x in r]
- print 'static const SANE_Range ' + n + ' = '
- print ' { ' + r[0] + ',' + r[1] + ',' + r[2] + ' };'
+ print ("static const SANE_Range " + n + " =")
+ print (" { " + r[0] + "," + r[1] + "," + r[2] + " };")
def genList(n, t, l):
@@ -227,13 +224,14 @@ def genList(n, t, l):
elif t == 'SANE_TYPE_STRING':
etype = 'SANE_String_Const'
l = ['SANE_I18N("%s")' % x for x in l] + ['NULL']
- print 'static const %s %s[%d] = {' % (etype, n, len(l))
+ print ("static const %s %s[%d] = {" % (etype, n, len(l)))
for x in l[0:-1]:
- print '\t' + x + ','
- print '\t' + l[-1] + ' };'
+ print ("\t" + x + ",")
+ print ("\t" + l[-1] + " };")
def genConstraints(options):
+ print ("")
for o in options:
if 'constraint' not in o: continue
c = o['constraint']
@@ -243,7 +241,6 @@ def genConstraints(options):
genMinMaxRange(oname, otype, c)
elif isinstance(c, list):
genList(oname, otype, c)
- print
def buildCodeVerbatim(o):
for f in ('name', 'title', 'desc', 'type', 'unit', 'size', 'cap',
@@ -283,12 +280,12 @@ def ccode(o):
o['code_size'] = code
if ('code_cap' not in o) and ('cap' in o):
- o['code_cap'] = reduce(lambda a,b: a+'|'+b, o['cap'])
+ o['code_cap'] = functools.reduce(lambda a,b: a+'|'+b, o['cap'])
else:
o['code_cap'] = '0'
if ('code_info' not in o) and ('info' in o):
- o['code_info'] = reduce(lambda a,b: a+'|'+b, o['info'])
+ o['code_info'] = functools.reduce(lambda a,b: a+'|'+b, o['info'])
else:
o['code_info'] = '0'
@@ -335,22 +332,21 @@ def ccode(o):
return o
def genBuildOptions(options):
- print """
-static
-int find_string_in_list(SANE_String_Const str, const SANE_String_Const *list)
-{
- int i;
- for (i = 0; list[i] && strcmp(str, list[i]) != 0; i++) {}
- return i;
-}
-
-static
-int build_option_descriptors(struct pixma_sane_t *ss)
-{
- SANE_Option_Descriptor *sod;
- option_descriptor_t *opt;
-
- memset(OPT_IN_CTX, 0, sizeof(OPT_IN_CTX));"""
+ print ("\nstatic")
+ print ("int find_string_in_list(SANE_String_Const str, const SANE_String_Const *list)")
+ print ("{")
+ print (" int i;")
+ print (" for (i = 0; list[i] && strcmp(str, list[i]) != 0; i++) {}")
+ print (" return i;")
+ print ("}")
+ print ("")
+ print ("static")
+ print ("int build_option_descriptors(struct pixma_sane_t *ss)")
+ print ("{")
+ print (" SANE_Option_Descriptor *sod;")
+ print (" option_descriptor_t *opt;")
+ print ("")
+ print (" memset(OPT_IN_CTX, 0, sizeof(OPT_IN_CTX));")
for o in options:
o = ccode(o)
@@ -370,10 +366,9 @@ int build_option_descriptors(struct pixma_sane_t *ss)
' OPT_IN_CTX[%(cname_opt)s].info = %(code_info)s;\n' \
'%(full_code_default)s'
sys.stdout.write(code % o)
- print
- print ' return 0;\n'
- print '}'
- print
+ print ("")
+ print (" return 0;")
+ print ("}\n")
g = Struct()
g.ngroups = 0
@@ -381,7 +376,8 @@ opt_prefix = 'opt_'
con_prefix = 'constraint_'
cnameMap = createCNameMap()
options = parseFile(sys.stdin)
-print "/* Automatically generated from pixma_sane.c */"
+print ("/* DO NOT EDIT THIS FILE! */")
+print ("/* Automatically generated from pixma.c */")
if (len(sys.argv) == 2) and (sys.argv[1] == 'h'):
genHeader(options)
else:
diff --git a/backend/plustek-usbshading.c b/backend/plustek-usbshading.c
index 98a28d9..e789b43 100644
--- a/backend/plustek-usbshading.c
+++ b/backend/plustek-usbshading.c
@@ -882,7 +882,7 @@ TOGAIN:
if( m_ScanParam.bDataType == SCANDATATYPE_Color ) {
RGBULongDef rgb, rgbSum;
- u_long dwLoop = len / 20 * 20;
+ u_long dwLoop = (len - start) / 20 * 20;
u_long dw10, dwGray, dwGrayMax;
rgb.Red = rgb.Green = rgb.Blue = dwGrayMax = 0;
@@ -923,7 +923,7 @@ TOGAIN:
} else {
u_long dwMax = 0, dwSum;
- u_long dwLoop = len / 20 * 20;
+ u_long dwLoop = (len - start) / 20 * 20;
u_long dw10;
for( dw = start; dwLoop; dwLoop-- ) {
@@ -951,7 +951,7 @@ TOGAIN:
RGBUShortDef max_rgb, min_rgb, tmp_rgb;
u_long dwR, dwG, dwB;
u_long dwDiv = 10;
- u_long dwLoop1 = len / dwDiv, dwLoop2;
+ u_long dwLoop1 = (len - start) / dwDiv, dwLoop2;
max_rgb.Red = max_rgb.Green = max_rgb.Blue = 0;
min_rgb.Red = min_rgb.Green = min_rgb.Blue = 0xffff;
diff --git a/backend/ricoh2_buffer.c b/backend/ricoh2_buffer.c
index e79a7f3..8cf86f3 100644
--- a/backend/ricoh2_buffer.c
+++ b/backend/ricoh2_buffer.c
@@ -44,14 +44,8 @@
#include "../include/sane/config.h"
-#include <memory.h>
#include <assert.h>
-
-#if defined(__APPLE__) && defined(__MACH__)
-#include <malloc/malloc.h>
-#else
-#include <malloc.h>
-#endif
+#include <stdlib.h>
#include "../include/sane/sanei_debug.h"
diff --git a/backend/test-picture.c b/backend/test-picture.c
index 46407dc..66374c7 100644
--- a/backend/test-picture.c
+++ b/backend/test-picture.c
@@ -155,8 +155,8 @@ init_picture_buffer (Test_Device * test_device, SANE_Byte ** buffer,
if (xfull < ppl)
{
if ((((SANE_Word) (xfull / p_size)) % 2)
- ^ !(line_count >
- (SANE_Word) (p_size + 0.5)))
+ ^ (!(line_count >
+ (SANE_Word) (p_size + 0.5))))
color = 0x0;
else
color = 0x1;
diff --git a/backend/test.c b/backend/test.c
index 3ead456..a1e186e 100644
--- a/backend/test.c
+++ b/backend/test.c
@@ -116,6 +116,12 @@ static SANE_Range int_constraint_range = {
2
};
+static SANE_Range gamma_range = {
+ 0,
+ 255,
+ 1
+};
+
static SANE_Range fixed_constraint_range = {
SANE_FIX (-42.17),
SANE_FIX (32767.9999),
@@ -184,6 +190,42 @@ static SANE_Int int_array_constraint_range[] = {
48, 6, 4, 92, 190, 16
};
+#define GAMMA_RED_SIZE 256
+#define GAMMA_GREEN_SIZE 256
+#define GAMMA_BLUE_SIZE 256
+#define GAMMA_ALL_SIZE 4096
+static SANE_Int gamma_red[GAMMA_RED_SIZE]; // initialized in init_options()
+static SANE_Int gamma_green[GAMMA_GREEN_SIZE];
+static SANE_Int gamma_blue[GAMMA_BLUE_SIZE];
+static SANE_Int gamma_all[GAMMA_ALL_SIZE];
+
+static void
+init_gamma_table(SANE_Int *tablePtr, SANE_Int count, SANE_Int max)
+{
+ for (int i=0; i<count; ++i) {
+ tablePtr[i] = (SANE_Int)(((double)i * max)/(double)count);
+ }
+}
+
+static void
+print_gamma_table(SANE_Int *tablePtr, SANE_Int count)
+{
+ char str[200];
+ str[0] = '\0';
+ DBG (5, "Gamma Table Size: %d\n", count);
+ for (int i=0; i<count; ++i) {
+ if (i%16 == 0 && strlen(str) > 0) {
+ DBG (5, "%s\n", str);
+ str[0] = '\0';
+ }
+ sprintf (str + strlen(str), " %04X", tablePtr[i]);
+ }
+ if (strlen(str) > 0) {
+ DBG (5, "%s\n", str);
+ }
+}
+
+
static SANE_Int int_array_constraint_word_list[] = {
-42, 0, -8, 17, 42, 42
};
@@ -923,6 +965,63 @@ init_options (Test_Device * test_device)
test_device->val[opt_int_array_constraint_range].wa =
&int_array_constraint_range[0];
+ /* opt_gamma_red */
+ init_gamma_table(gamma_red, GAMMA_RED_SIZE, gamma_range.max);
+ od = &test_device->opt[opt_gamma_red];
+ od->name = SANE_NAME_GAMMA_VECTOR_R;
+ od->title = SANE_TITLE_GAMMA_VECTOR_R;
+ od->desc = SANE_DESC_GAMMA_VECTOR_R;
+ od->type = SANE_TYPE_INT;
+ od->unit = SANE_UNIT_NONE;
+ od->size = 256 * sizeof (SANE_Word);
+ od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED;
+ od->constraint_type = SANE_CONSTRAINT_RANGE;
+ od->constraint.range = &gamma_range;
+ test_device->val[opt_gamma_red].wa = &gamma_red[0];
+
+ /* opt_gamma_green */
+ init_gamma_table(gamma_green, GAMMA_GREEN_SIZE, gamma_range.max);
+ od = &test_device->opt[opt_gamma_green];
+ od->name = SANE_NAME_GAMMA_VECTOR_G;
+ od->title = SANE_TITLE_GAMMA_VECTOR_G;
+ od->desc = SANE_DESC_GAMMA_VECTOR_G;
+ od->type = SANE_TYPE_INT;
+ od->unit = SANE_UNIT_NONE;
+ od->size = 256 * sizeof (SANE_Word);
+ od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED;
+ od->constraint_type = SANE_CONSTRAINT_RANGE;
+ od->constraint.range = &gamma_range;
+ test_device->val[opt_gamma_green].wa = &gamma_green[0];
+
+ /* opt_gamma_blue */
+ init_gamma_table(gamma_blue, GAMMA_BLUE_SIZE, gamma_range.max);
+ od = &test_device->opt[opt_gamma_blue];
+ od->name = SANE_NAME_GAMMA_VECTOR_B;
+ od->title = SANE_TITLE_GAMMA_VECTOR_B;
+ od->desc = SANE_DESC_GAMMA_VECTOR_B;
+ od->type = SANE_TYPE_INT;
+ od->unit = SANE_UNIT_NONE;
+ od->size = 256 * sizeof (SANE_Word);
+ od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED;
+ od->constraint_type = SANE_CONSTRAINT_RANGE;
+ od->constraint.range = &gamma_range;
+ test_device->val[opt_gamma_blue].wa = &gamma_blue[0];
+
+ /* opt_gamma_all */
+ init_gamma_table(gamma_all, GAMMA_ALL_SIZE, gamma_range.max);
+ print_gamma_table(gamma_all, GAMMA_ALL_SIZE);
+ od = &test_device->opt[opt_gamma_all];
+ od->name = SANE_NAME_GAMMA_VECTOR;
+ od->title = SANE_TITLE_GAMMA_VECTOR;
+ od->desc = SANE_DESC_GAMMA_VECTOR;
+ od->type = SANE_TYPE_INT;
+ od->unit = SANE_UNIT_NONE;
+ od->size = GAMMA_ALL_SIZE * sizeof (SANE_Word);
+ od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED;
+ od->constraint_type = SANE_CONSTRAINT_RANGE;
+ od->constraint.range = &gamma_range;
+ test_device->val[opt_gamma_all].wa = &gamma_all[0];
+
/* opt_int_array_constraint_word_list */
od = &test_device->opt[opt_int_array_constraint_word_list];
od->name = "int-constraint-array-constraint-word-list";
@@ -2071,11 +2170,21 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action,
break;
case opt_int_array: /* Word array */
case opt_int_array_constraint_range:
+ case opt_gamma_red:
+ case opt_gamma_green:
+ case opt_gamma_blue:
+ case opt_gamma_all:
case opt_int_array_constraint_word_list:
memcpy (test_device->val[option].wa, value,
test_device->opt[option].size);
DBG (4, "sane_control_option: set option %d (%s) to %p\n",
option, test_device->opt[option].name, (void *) value);
+ if (option == opt_gamma_all) {
+ print_gamma_table(gamma_all, GAMMA_ALL_SIZE);
+ }
+ if (option == opt_gamma_red) {
+ print_gamma_table(gamma_red, GAMMA_RED_SIZE);
+ }
break;
/* options with side-effects */
case opt_print_options:
@@ -2298,6 +2407,10 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action,
break;
case opt_int_array: /* Int array */
case opt_int_array_constraint_range:
+ case opt_gamma_red:
+ case opt_gamma_green:
+ case opt_gamma_blue:
+ case opt_gamma_all:
case opt_int_array_constraint_word_list:
memcpy (value, test_device->val[option].wa,
test_device->opt[option].size);
diff --git a/backend/test.h b/backend/test.h
index dcd54b6..5b1b82b 100644
--- a/backend/test.h
+++ b/backend/test.h
@@ -100,6 +100,10 @@ typedef enum
opt_int_constraint_word_list,
opt_int_array,
opt_int_array_constraint_range,
+ opt_gamma_red,
+ opt_gamma_green,
+ opt_gamma_blue,
+ opt_gamma_all,
opt_int_array_constraint_word_list,
opt_fixed_group,
opt_fixed,
diff --git a/backend/umax_pp_low.c b/backend/umax_pp_low.c
index ddcf3da..569f824 100644
--- a/backend/umax_pp_low.c
+++ b/backend/umax_pp_low.c
@@ -935,7 +935,7 @@ sanei_umax_pp_initPort (int port, const char *name)
char strmodes[160];
# endif
# endif
-# ifdef HAVE_DEV_PPBUS_PP_H
+# ifdef HAVE_DEV_PPBUS_PPI_H
int found = 0;
int fd;
# endif
diff --git a/backend/v4l.c b/backend/v4l.c
index 006e7f7..f9245d0 100644
--- a/backend/v4l.c
+++ b/backend/v4l.c
@@ -72,7 +72,6 @@
#include "../include/sane/saneopts.h"
#include <sys/ioctl.h>
-#include <asm/types.h> /* XXX glibc */
#define BACKEND_NAME v4l
#include "../include/sane/sanei_backend.h"
@@ -1046,7 +1045,7 @@ sane_start (SANE_Handle handle)
/* v4l1 actually returns BGR when we ask for RGB, so convert it */
if (s->pict.palette == VIDEO_PALETTE_RGB24)
{
- __u32 loop;
+ uint32_t loop;
DBG (3, "sane_start: converting from BGR to RGB\n");
for (loop = 0; loop < (s->window.width * s->window.height * 3); loop += 3)
{
diff --git a/backend/v4l.h b/backend/v4l.h
index e6673d0..7698be1 100644
--- a/backend/v4l.h
+++ b/backend/v4l.h
@@ -29,145 +29,6 @@
#ifndef v4l_h
#define v4l_h
-#ifndef __LINUX_VIDEODEV_H
-/* Kernel interface */
-/* Only the stuff we need. For more features, more defines are needed */
-
-#define VID_TYPE_CAPTURE 1 /* Can capture */
-#define VID_TYPE_TUNER 2 /* Can tune */
-#define VID_TYPE_TELETEXT 4 /* Does teletext */
-#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */
-#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */
-#define VID_TYPE_CLIPPING 32 /* Can clip */
-#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */
-#define VID_TYPE_SCALES 128 /* Scalable */
-#define VID_TYPE_MONOCHROME 256 /* Monochrome only */
-#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */
-#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */
-#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */
-#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */
-#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */
-
-struct video_capability
-{
- char name[32];
- int type;
- int channels; /* Num channels */
- int audios; /* Num audio devices */
- int maxwidth; /* Supported width */
- int maxheight; /* And height */
- int minwidth; /* Supported width */
- int minheight; /* And height */
-};
-
-struct video_picture
-{
- __u16 brightness;
- __u16 hue;
- __u16 colour;
- __u16 contrast;
- __u16 whiteness; /* Black and white only */
- __u16 depth; /* Capture depth */
- __u16 palette; /* Palette in use */
-#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */
-#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */
-#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */
-#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */
-#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */
-#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */
-#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */
-#define VIDEO_PALETTE_YUYV 8
-#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */
-#define VIDEO_PALETTE_YUV420 10
-#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */
-#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */
-#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */
-#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */
-#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */
-#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */
-#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */
-#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */
-};
-
-struct video_window
-{
- __u32 x,y; /* Position of window */
- __u32 width,height; /* Its size */
- __u32 chromakey;
- __u32 flags;
- struct video_clip *clips; /* Set only */
- int clipcount;
-#define VIDEO_WINDOW_INTERLACE 1
-#define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */
-#define VIDEO_CLIP_BITMAP -1
-/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
-#define VIDEO_CLIPMAP_SIZE (128 * 625)
-};
-
-#define VIDEO_MAX_FRAME 32
-
-struct video_mbuf
-{
- int size; /* Total memory to map */
- int frames; /* Frames */
- int offsets[VIDEO_MAX_FRAME];
-};
-
-struct video_mmap
-{
- unsigned int frame; /* Frame (0 - n) for double buffer */
- int height,width;
- unsigned int format; /* should be VIDEO_PALETTE_* */
-};
-
-struct video_channel
-{
- int channel;
- char name[32];
- int tuners;
- __u32 flags;
-#define VIDEO_VC_TUNER 1 /* Channel has a tuner */
-#define VIDEO_VC_AUDIO 2 /* Channel has audio */
- __u16 type;
-#define VIDEO_TYPE_TV 1
-#define VIDEO_TYPE_CAMERA 2
- __u16 norm; /* Norm set by channel */
-};
-
-#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */
-#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */
-#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */
-#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */
-#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */
-#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */
-#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */
-#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */
-#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */
-#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
-#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */
-#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */
-#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
-#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */
-#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */
-#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */
-#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */
-#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */
-#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */
-#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */
-#define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */
-#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */
-#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */
-#define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */
-#define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */
-#define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */
-#define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */
-#define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */
-#define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */
-
-
-/* end of kernel interface */
-#endif /* !__LINUX_VIDEODEV_H */
-
#include <../include/sane/sane.h>
#define MAX_CHANNELS 32
diff --git a/backend/xerox_mfp.conf.in b/backend/xerox_mfp.conf.in
index 39bf669..4fcbeb6 100644
--- a/backend/xerox_mfp.conf.in
+++ b/backend/xerox_mfp.conf.in
@@ -245,6 +245,9 @@ usb 0x0924 0x4293
#Xerox WorkCentre 3220
usb 0x0924 0x4294
+#Xerox WorkCentre 3225
+usb 0x0924 0x42dc
+
###################
### Dell Models ###
###################