diff options
Diffstat (limited to 'backend/genesys')
73 files changed, 13089 insertions, 17033 deletions
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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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, ®s, 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 |