diff options
Diffstat (limited to 'backend/genesys_low.h')
-rw-r--r-- | backend/genesys_low.h | 1901 |
1 files changed, 1349 insertions, 552 deletions
diff --git a/backend/genesys_low.h b/backend/genesys_low.h index 56627b4..e750808 100644 --- a/backend/genesys_low.h +++ b/backend/genesys_low.h @@ -1,4 +1,4 @@ -/* sane - Scanner Access Now Easy. +/* sane - Scanner Access Now Easy. Copyright (C) 2003 Oliver Rauch Copyright (C) 2003, 2004 Henning Meier-Geinitz <henning@meier-geinitz.de> @@ -81,56 +81,20 @@ #include "../include/_stdint.h" -#ifndef UNIT_TESTING -#define GENESYS_STATIC static -#else -#define GENESYS_STATIC -#endif - -#define DBG_error0 0 /* errors/warnings printed even with devuglevel 0 */ -#define DBG_error 1 /* fatal errors */ -#define DBG_init 2 /* initialization and scanning time messages */ -#define DBG_warn 3 /* warnings and non-fatal errors */ -#define DBG_info 4 /* informational messages */ -#define DBG_proc 5 /* starting/finishing functions */ -#define DBG_io 6 /* io functions */ -#define DBG_io2 7 /* io functions that are called very often */ -#define DBG_data 8 /* log image data */ - -/** - * call a function and return on error - */ -#define RIE(function) \ - do { status = function; \ - if (status != SANE_STATUS_GOOD) \ - { \ - DBG(DBG_error, "%s: %s\n", __func__, sane_strstatus (status)); \ - return status; \ - } \ - } while (SANE_FALSE) - -#define RIEF(function, mem) \ - do { status = function; \ - if (status != SANE_STATUS_GOOD) \ - { \ - free(mem); \ - DBG(DBG_error, "%s: %s\n", __func__, sane_strstatus (status)); \ - return status; \ - } \ - } while (SANE_FALSE) - -#define RIEF2(function, mem1, mem2) \ - do { status = function; \ - if (status != SANE_STATUS_GOOD) \ - { \ - free(mem1); \ - free(mem2); \ - return status; \ - } \ - } while (SANE_FALSE) - -#define DBGSTART DBG (DBG_proc, "%s start\n", __func__); -#define DBGCOMPLETED DBG (DBG_proc, "%s completed\n", __func__); +#include "genesys_error.h" +#include "genesys_sanei.h" +#include "genesys_serialize.h" + +#include <algorithm> +#include <array> +#include <cstring> +#include <functional> +#include <iostream> +#include <limits> +#include <memory> +#include <stdexcept> +#include <string> +#include <vector> #define FREE_IFNOT_NULL(x) if(x!=NULL) { free(x); x=NULL;} @@ -163,11 +127,12 @@ #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_HALF_CCD_MODE (1 << 15) /**< scanner has setting for half ccd mode */ #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) #define GENESYS_HAS_NO_BUTTONS 0 /**< scanner has no supported button */ #define GENESYS_HAS_SCAN_SW (1 << 0) /**< scanner has SCAN button */ @@ -207,9 +172,6 @@ #define BULK_RAM 0x00 #define BULK_REGISTER 0x11 -#define BULKIN_MAXSIZE 0xFE00 -#define GL646_BULKIN_MAXSIZE 0xFFC0 -#define GL646_BULKIN_MINSIZE 0x0800 #define BULKOUT_MAXSIZE 0xF000 /* AFE values */ @@ -236,77 +198,619 @@ #define FEBUSY 0x02 #define MOTORENB 0x01 -typedef struct Genesys_Register_Set +#define GENESYS_MAX_REGS 256 + +enum class ScanMethod : unsigned { + // normal scan method + FLATBED = 0, + // scan using transparency adaptor + TRANSPARENCY = 1, + // scan using transparency adaptor via infrared channel + TRANSPARENCY_INFRARED = 2 +}; + +inline void serialize(std::istream& str, ScanMethod& x) +{ + unsigned value; + serialize(str, value); + x = static_cast<ScanMethod>(value); +} + +inline void serialize(std::ostream& str, ScanMethod& x) +{ + unsigned value = static_cast<unsigned>(x); + serialize(str, value); +} + +enum class ScanColorMode : unsigned { + LINEART = 0, + HALFTONE, + GRAY, + COLOR_SINGLE_PASS +}; + +inline void serialize(std::istream& str, ScanColorMode& x) +{ + unsigned value; + serialize(str, value); + x = static_cast<ScanColorMode>(value); +} + +inline void serialize(std::ostream& str, ScanColorMode& x) +{ + unsigned value = static_cast<unsigned>(x); + serialize(str, value); +} + +enum class ColorFilter : unsigned { + RED = 0, + GREEN, + BLUE, + NONE +}; + +inline void serialize(std::istream& str, ColorFilter& x) +{ + unsigned value; + serialize(str, value); + x = static_cast<ColorFilter>(value); +} + +inline void serialize(std::ostream& str, ColorFilter& x) +{ + unsigned value = static_cast<unsigned>(x); + serialize(str, value); +} + +struct GenesysRegister { + uint16_t address = 0; + uint8_t value = 0; +}; + +inline bool operator<(const GenesysRegister& lhs, const GenesysRegister& rhs) +{ + return lhs.address < rhs.address; +} + +struct GenesysRegisterSetState { + bool is_lamp_on = false; + bool is_xpa_on = false; +}; + +class Genesys_Register_Set { +public: + using container = std::vector<GenesysRegister>; + using iterator = typename container::iterator; + using const_iterator = typename container::const_iterator; + + // FIXME: this shouldn't live here, but in a separate struct that contains Genesys_Register_Set + GenesysRegisterSetState state; + + enum Options { + SEQUENTIAL = 1 + }; + + Genesys_Register_Set() + { + registers_.reserve(GENESYS_MAX_REGS); + } + + // by default the register set is sorted by address. In certain cases it's importand to send + // the registers in certain order: use the SEQUENTIAL option for that + Genesys_Register_Set(Options opts) : Genesys_Register_Set() + { + if ((opts & SEQUENTIAL) == SEQUENTIAL) { + sorted_ = false; + } + } + + void init_reg(uint16_t address, uint8_t default_value) + { + if (find_reg_index(address) >= 0) { + set8(address, default_value); + return; + } + GenesysRegister reg; + reg.address = address; + reg.value = default_value; + registers_.push_back(reg); + if (sorted_) + std::sort(registers_.begin(), registers_.end()); + } + + void remove_reg(uint16_t address) + { + int i = find_reg_index(address); + if (i < 0) { + throw std::runtime_error("the register does not exist"); + } + registers_.erase(registers_.begin() + i); + } + + GenesysRegister& find_reg(uint16_t address) + { + int i = find_reg_index(address); + if (i < 0) { + throw std::runtime_error("the register does not exist"); + } + return registers_[i]; + } + + const GenesysRegister& find_reg(uint16_t address) const + { + int i = find_reg_index(address); + if (i < 0) { + throw std::runtime_error("the register does not exist"); + } + return registers_[i]; + } + + GenesysRegister* find_reg_address(uint16_t address) + { + return &find_reg(address); + } + + const GenesysRegister* find_reg_address(uint16_t address) const + { + return &find_reg(address); + } + + void set8(uint16_t address, uint8_t value) + { + find_reg(address).value = value; + } + + void set8_mask(uint16_t address, uint8_t value, uint8_t mask) + { + auto& reg = find_reg(address); + reg.value = (reg.value & ~mask) | value; + } + + void set16(uint16_t address, uint16_t value) + { + find_reg(address).value = (value >> 8) & 0xff; + find_reg(address + 1).value = value & 0xff; + } + + void set24(uint16_t address, uint32_t value) + { + find_reg(address).value = (value >> 16) & 0xff; + find_reg(address + 1).value = (value >> 8) & 0xff; + find_reg(address + 2).value = value & 0xff; + } + + uint8_t get8(uint16_t address) const + { + return find_reg(address).value; + } + + uint16_t get16(uint16_t address) const + { + return (find_reg(address).value << 8) | find_reg(address + 1).value; + } + + uint32_t get24(uint16_t address) const + { + return (find_reg(address).value << 16) | + (find_reg(address + 1).value << 8) | + find_reg(address + 2).value; + } + + void clear() { registers_.clear(); } + size_t size() const { return registers_.size(); } + + iterator begin() { return registers_.begin(); } + const_iterator begin() const { return registers_.begin(); } + + iterator end() { return registers_.end(); } + const_iterator end() const { return registers_.end(); } + +private: + int find_reg_index(uint16_t address) const + { + if (!sorted_) { + for (size_t i = 0; i < registers_.size(); i++) { + if (registers_[i].address == address) { + return i; + } + } + return -1; + } + + GenesysRegister search; + search.address = address; + auto it = std::lower_bound(registers_.begin(), registers_.end(), search); + if (it == registers_.end()) + return -1; + if (it->address != address) + return -1; + return std::distance(registers_.begin(), it); + } + + // registers are stored in a sorted vector + bool sorted_ = true; + std::vector<GenesysRegister> registers_; +}; + +template<class T, size_t Size> +struct AssignableArray : public std::array<T, Size> { + AssignableArray() = default; + AssignableArray(const AssignableArray&) = default; + AssignableArray& operator=(const AssignableArray&) = default; + + AssignableArray& operator=(std::initializer_list<T> init) + { + if (init.size() != std::array<T, Size>::size()) + throw std::runtime_error("An array of incorrect size assigned"); + std::copy(init.begin(), init.end(), std::array<T, Size>::begin()); + return *this; + } +}; + +struct GenesysRegisterSetting { + GenesysRegisterSetting() = default; + + GenesysRegisterSetting(uint16_t p_address, uint8_t p_value) : + address(p_address), value(p_value) + {} + + GenesysRegisterSetting(uint16_t p_address, uint8_t p_value, uint8_t p_mask) : + address(p_address), value(p_value), mask(p_mask) + {} + + uint16_t address = 0; + uint8_t value = 0; + uint8_t mask = 0xff; + + bool operator==(const GenesysRegisterSetting& other) const + { + return address == other.address && value == other.value && mask == other.mask; + } +}; + +template<class Stream> +void serialize(Stream& str, GenesysRegisterSetting& reg) +{ + serialize(str, reg.address); + serialize(str, reg.value); + serialize(str, reg.mask); +} + +class GenesysRegisterSettingSet { +public: + using container = std::vector<GenesysRegisterSetting>; + using iterator = typename container::iterator; + using const_iterator = typename container::const_iterator; + + GenesysRegisterSettingSet() = default; + GenesysRegisterSettingSet(std::initializer_list<GenesysRegisterSetting> ilist) : regs_(ilist) {} + + iterator begin() { return regs_.begin(); } + const_iterator begin() const { return regs_.begin(); } + iterator end() { return regs_.end(); } + const_iterator end() const { return regs_.end(); } + + GenesysRegisterSetting& operator[](size_t i) { return regs_[i]; } + const GenesysRegisterSetting& operator[](size_t i) const { return regs_[i]; } + + size_t size() const { return regs_.size(); } + bool empty() const { return regs_.empty(); } + void clear() { regs_.clear(); } + + void push_back(GenesysRegisterSetting reg) { regs_.push_back(reg); } + + void merge(const GenesysRegisterSettingSet& other) + { + for (const auto& reg : other) { + set_value(reg.address, reg.value); + } + } + + uint8_t get_value(uint16_t address) const + { + for (const auto& reg : regs_) { + if (reg.address == address) + return reg.value; + } + throw std::runtime_error("Unknown register"); + } + + void set_value(uint16_t address, uint8_t value) + { + for (auto& reg : regs_) { + if (reg.address == address) { + reg.value = value; + return; + } + } + push_back(GenesysRegisterSetting(address, value)); + } + + friend void serialize(std::istream& str, GenesysRegisterSettingSet& reg); + friend void serialize(std::ostream& str, GenesysRegisterSettingSet& reg); + + bool operator==(const GenesysRegisterSettingSet& other) const + { + return regs_ == other.regs_; + } + +private: + std::vector<GenesysRegisterSetting> regs_; +}; + +inline void serialize(std::istream& str, GenesysRegisterSettingSet& reg) +{ + reg.clear(); + const size_t max_register_address = + 1 << (sizeof(GenesysRegisterSetting::address) * CHAR_BIT); + serialize(str, reg.regs_, max_register_address); +} + +inline void serialize(std::ostream& str, GenesysRegisterSettingSet& reg) +{ + serialize(str, reg.regs_); +} + +struct GenesysFrontendLayout { - uint16_t address; - uint8_t value; -} Genesys_Register_Set; + std::array<uint16_t, 3> offset_addr = {}; + std::array<uint16_t, 3> gain_addr = {}; + + bool operator==(const GenesysFrontendLayout& other) const + { + return offset_addr == other.offset_addr && gain_addr == other.gain_addr; + } +}; /** @brief Data structure to set up analog frontend. - * The analog frontend converts analog value from image sensor to - * digital value. It has its own control registers which are set up - * with this structure. The values are written using sanei_genesys_fe_write_data. - * The actual register addresses they map to depends on the frontend used. - * @see sanei_genesys_fe_write_data + The analog frontend converts analog value from image sensor to digital value. It has its own + control registers which are set up with this structure. The values are written using + sanei_genesys_fe_write_data. */ -typedef struct +struct Genesys_Frontend { - uint8_t fe_id; /**< id of the frontend description */ - uint8_t reg[4]; /**< values to set up frontend control register, they - usually map to analog register 0x00 to 0x03 */ - uint8_t sign[3]; /**< sets the sign of the digital value */ - uint8_t offset[3]; /**< offset correction to apply to signal, most often - maps to frontend register 0x20-0x22 */ - uint8_t gain[3]; /**< amplification to apply to signal, most often - maps to frontend register 0x28-0x2a */ - uint8_t reg2[3]; /**< extra control registers */ -} Genesys_Frontend; - -typedef struct + Genesys_Frontend() = default; + + // id of the frontend description + uint8_t fe_id = 0; + + // all registers of the frontend + GenesysRegisterSettingSet regs; + + // extra control registers + std::array<uint8_t, 3> reg2 = {}; + + GenesysFrontendLayout layout; + + void set_offset(unsigned which, uint8_t value) + { + regs.set_value(layout.offset_addr[which], value); + } + + void set_gain(unsigned which, uint8_t value) + { + regs.set_value(layout.gain_addr[which], value); + } + + uint8_t get_offset(unsigned which) const + { + return regs.get_value(layout.offset_addr[which]); + } + + uint8_t get_gain(unsigned which) const + { + return regs.get_value(layout.gain_addr[which]); + } + + bool operator==(const Genesys_Frontend& other) const + { + return fe_id == other.fe_id && + regs == other.regs && + reg2 == other.reg2 && + layout == other.layout; + } +}; + +template<class Stream> +void serialize(Stream& str, Genesys_Frontend& x) { - uint8_t sensor_id; /**< id of the sensor description */ - int optical_res; - int black_pixels; - int dummy_pixel; /* value of dummy register. */ - int CCD_start_xoffset; /* last pixel of CCD margin at optical resolution */ - int sensor_pixels; /* total pixels used by the sensor */ - int fau_gain_white_ref; /* TA CCD target code (reference gain) */ - int gain_white_ref; /* CCD target code (reference gain) */ - uint8_t regs_0x08_0x0b[4]; - uint8_t regs_0x10_0x1d[14]; - uint8_t regs_0x52_0x5e[13]; - float gamma[3]; /**< red, green and blue gamma coefficient for default gamma tables */ - uint16_t *gamma_table[3]; /**< sensor specific gamma tables */ -} Genesys_Sensor; - -typedef struct + serialize(str, x.fe_id); + serialize_newline(str); + serialize(str, x.regs); + serialize_newline(str); + serialize(str, x.reg2); + serialize_newline(str); + serialize(str, x.layout.offset_addr); + serialize(str, x.layout.gain_addr); +} + +struct SensorExposure { + uint16_t red, green, blue; +}; + +struct Genesys_Sensor { + + Genesys_Sensor() = default; + ~Genesys_Sensor() = default; + + // id of the sensor description + uint8_t sensor_id = 0; + int optical_res = 0; + + // the minimum and maximum resolution this sensor is usable at. -1 means that the resolution + // can be any. + int min_resolution = -1; + int max_resolution = -1; + + // the scan method used with the sensor + ScanMethod method = ScanMethod::FLATBED; + + // CCD may present itself as half or quarter-size CCD on certain resolutions + int ccd_size_divisor = 1; + + 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) + int gain_white_ref = 0; + + // red, green and blue initial exposure values + SensorExposure exposure; + + int exposure_lperiod = -1; + + GenesysRegisterSettingSet custom_regs; + GenesysRegisterSettingSet custom_fe_regs; + + // red, green and blue gamma coefficient for default gamma tables + AssignableArray<float, 3> gamma; + + int get_ccd_size_divisor_for_dpi(int xres) const + { + if (ccd_size_divisor >= 4 && xres * 4 <= optical_res) { + return 4; + } + if (ccd_size_divisor >= 2 && xres * 2 <= optical_res) { + return 2; + } + return 1; + } + + bool operator==(const Genesys_Sensor& other) const + { + return sensor_id == other.sensor_id && + optical_res == other.optical_res && + min_resolution == other.min_resolution && + max_resolution == other.max_resolution && + method == other.method && + ccd_size_divisor == other.ccd_size_divisor && + 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.blue == other.exposure.blue && + exposure.green == other.exposure.green && + exposure.red == other.exposure.red && + exposure_lperiod == other.exposure_lperiod && + custom_regs == other.custom_regs && + custom_fe_regs == other.custom_fe_regs && + gamma == other.gamma; + } +}; + +template<class Stream> +void serialize(Stream& str, Genesys_Sensor& x) { - uint8_t gpo_id; /**< id of the gpo description */ - uint8_t value[2]; /**< registers 0x6c and 0x6d on gl843 */ - uint8_t enable[2]; /**< registers 0x6e and 0x6F on gl843 */ -} Genesys_Gpo; + serialize(str, x.sensor_id); + serialize(str, x.optical_res); + serialize(str, x.min_resolution); + serialize(str, x.max_resolution); + serialize(str, x.method); + serialize(str, x.ccd_size_divisor); + 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); + serialize(str, x.exposure.blue); + serialize(str, x.exposure.green); + serialize(str, x.exposure.red); + serialize(str, x.exposure_lperiod); + serialize_newline(str); + serialize(str, x.custom_regs); + serialize_newline(str); + serialize(str, x.custom_fe_regs); + serialize_newline(str); + serialize(str, x.gamma); +} -typedef struct +struct Genesys_Gpo { - SANE_Int maximum_start_speed; /* maximum speed allowed when accelerating from standstill. Unit: pixeltime/step */ - SANE_Int maximum_speed; /* maximum speed allowed. Unit: pixeltime/step */ - SANE_Int minimum_steps; /* number of steps used for default curve */ - float g; /* power for non-linear acceleration curves. */ -/* vs*(1-i^g)+ve*(i^g) where - vs = start speed, ve = end speed, - i = 0.0 for first entry and i = 1.0 for last entry in default table*/ -} Genesys_Motor_Slope; + Genesys_Gpo() = default; + + Genesys_Gpo(uint8_t id, const std::array<uint8_t, 2>& v, const std::array<uint8_t, 2>& e) + { + gpo_id = id; + value[0] = v[0]; + value[1] = v[1]; + enable[0] = e[0]; + enable[1] = e[1]; + } + // Genesys_Gpo + uint8_t gpo_id = 0; -typedef struct + // registers 0x6c and 0x6d on GL841, GL842, GL843, GL846, GL848 and possibly others + uint8_t value[2] = { 0, 0 }; + + // registers 0x6e and 0x6f on GL841, GL842, GL843, GL846, GL848 and possibly others + uint8_t enable[2] = { 0, 0 }; +}; + +struct Genesys_Motor_Slope +{ + Genesys_Motor_Slope() = default; + Genesys_Motor_Slope(int p_maximum_start_speed, int p_maximum_speed, int p_minimum_steps, + float p_g) : + maximum_start_speed(p_maximum_start_speed), + maximum_speed(p_maximum_speed), + minimum_steps(p_minimum_steps), + g(p_g) + {} + + // maximum speed allowed when accelerating from standstill. Unit: pixeltime/step + int maximum_start_speed = 0; + // maximum speed allowed. Unit: pixeltime/step + int maximum_speed = 0; + // number of steps used for default curve + int minimum_steps = 0; + + /* power for non-linear acceleration curves. + vs*(1-i^g)+ve*(i^g) where + vs = start speed, ve = end speed, + i = 0.0 for first entry and i = 1.0 for last entry in default table + */ + float g = 0; +}; + + +struct Genesys_Motor { - uint8_t motor_id; /**< id of the motor description */ - SANE_Int base_ydpi; /* motor base steps. Unit: 1/" */ - SANE_Int optical_ydpi; /* maximum resolution in y-direction. Unit: 1/" */ - SANE_Int max_step_type; /* maximum step type. 0-2 */ - SANE_Int power_mode_count; /* number of power modes*/ - Genesys_Motor_Slope slopes[2][3]; /* slopes to derive individual slopes from */ -} Genesys_Motor; + Genesys_Motor() = default; + Genesys_Motor(uint8_t p_motor_id, int p_base_ydpi, int p_optical_ydpi, int p_max_step_type, + int p_power_mode_count, + const std::vector<std::vector<Genesys_Motor_Slope>>& p_slopes) : + motor_id(p_motor_id), + base_ydpi(p_base_ydpi), + optical_ydpi(p_optical_ydpi), + max_step_type(p_max_step_type), + power_mode_count(p_power_mode_count), + slopes(p_slopes) + {} + + // id of the motor description + uint8_t motor_id = 0; + // motor base steps. Unit: 1/inch + int base_ydpi = 0; + // maximum resolution in y-direction. Unit: 1/inch + int optical_ydpi = 0; + // maximum step type. 0-2 + int max_step_type = 0; + // number of power modes + int power_mode_count = 0; + // slopes to derive individual slopes from + std::vector<std::vector<Genesys_Motor_Slope>> slopes; +}; typedef enum Genesys_Color_Order { @@ -329,116 +833,175 @@ Genesys_Color_Order; #define GENESYS_GL123 123 #define GENESYS_GL124 124 -#define GENESYS_MAX_REGS 256 +enum Genesys_Model_Type +{ + MODEL_UMAX_ASTRA_4500 = 0, + MODEL_CANON_LIDE_50, + MODEL_PANASONIC_KV_SS080, + MODEL_HP_SCANJET_4850C, + MODEL_HP_SCANJET_G4010, + MODEL_HP_SCANJET_G4050, + MODEL_CANON_CANOSCAN_4400F, + MODEL_CANON_CANOSCAN_8400F, + MODEL_CANON_CANOSCAN_8600F, + MODEL_CANON_LIDE_100, + MODEL_CANON_LIDE_110, + MODEL_CANON_LIDE_120, + MODEL_CANON_LIDE_210, + MODEL_CANON_LIDE_220, + MODEL_CANON_CANOSCAN_5600F, + MODEL_CANON_LIDE_700F, + MODEL_CANON_LIDE_200, + MODEL_CANON_LIDE_60, + MODEL_CANON_LIDE_80, + MODEL_HP_SCANJET_2300C, + MODEL_HP_SCANJET_2400C, + MODEL_VISIONEER_STROBE_XP200, + MODEL_HP_SCANJET_3670C, + MODEL_PLUSTEK_OPTICPRO_ST12, + MODEL_PLUSTEK_OPTICPRO_ST24, + MODEL_MEDION_MD5345, + MODEL_VISIONEER_STROBE_XP300, + MODEL_SYSCAN_DOCKETPORT_665, + MODEL_VISIONEER_ROADWARRIOR, + MODEL_SYSCAN_DOCKETPORT_465, + MODEL_VISIONEER_STROBE_XP100_REVISION3, + MODEL_PENTAX_DSMOBILE_600, + MODEL_SYSCAN_DOCKETPORT_467, + MODEL_SYSCAN_DOCKETPORT_685, + MODEL_SYSCAN_DOCKETPORT_485, + MODEL_DCT_DOCKETPORT_487, + MODEL_VISIONEER_7100, + MODEL_XEROX_2400, + MODEL_XEROX_TRAVELSCANNER_100, + MODEL_PLUSTEK_OPTICPRO_3600, + MODEL_HP_SCANJET_N6310, + MODEL_PLUSTEK_OPTICBOOK_3800, + MODEL_CANON_IMAGE_FORMULA_101 +}; -#define DAC_WOLFSON_UMAX 0 -#define DAC_WOLFSON_ST12 1 -#define DAC_WOLFSON_ST24 2 -#define DAC_WOLFSON_5345 3 -#define DAC_WOLFSON_HP2400 4 -#define DAC_WOLFSON_HP2300 5 -#define DAC_CANONLIDE35 6 -#define DAC_AD_XP200 7 /* Analog Device frontend */ -#define DAC_WOLFSON_XP300 8 -#define DAC_WOLFSON_HP3670 9 -#define DAC_WOLFSON_DSM600 10 -#define DAC_CANONLIDE200 11 -#define DAC_KVSS080 12 -#define DAC_G4050 13 -#define DAC_CANONLIDE110 14 -#define DAC_PLUSTEK_3600 15 -#define DAC_CANONLIDE700 16 -#define DAC_CS8400F 17 -#define DAC_IMG101 18 -#define DAC_PLUSTEK3800 19 -#define DAC_CANONLIDE80 20 -#define DAC_CANONLIDE120 21 - -#define CCD_UMAX 0 -#define CCD_ST12 1 /* SONY ILX548: 5340 Pixel ??? */ -#define CCD_ST24 2 /* SONY ILX569: 10680 Pixel ??? */ -#define CCD_5345 3 -#define CCD_HP2400 4 -#define CCD_HP2300 5 -#define CCD_CANONLIDE35 6 -#define CIS_XP200 7 /* CIS sensor for Strobe XP200 */ - /* 8 is unused currently */ -#define CCD_HP3670 9 -#define CCD_DP665 10 -#define CCD_ROADWARRIOR 11 -#define CCD_DSMOBILE600 12 -#define CCD_XP300 13 -#define CCD_DP685 14 -#define CIS_CANONLIDE200 15 -#define CIS_CANONLIDE100 16 -#define CCD_KVSS080 17 -#define CCD_G4050 18 -#define CIS_CANONLIDE110 19 -#define CCD_PLUSTEK_3600 20 -#define CCD_HP_N6310 21 -#define CIS_CANONLIDE700 22 -#define CCD_CS4400F 23 -#define CCD_CS8400F 24 -#define CCD_IMG101 25 -#define CCD_PLUSTEK3800 26 -#define CIS_CANONLIDE210 27 -#define CIS_CANONLIDE80 28 -#define CIS_CANONLIDE220 29 -#define CIS_CANONLIDE120 30 - -#define GPO_UMAX 0 -#define GPO_ST12 1 -#define GPO_ST24 2 -#define GPO_5345 3 -#define GPO_HP2400 4 -#define GPO_HP2300 5 -#define GPO_CANONLIDE35 6 -#define GPO_XP200 7 -#define GPO_XP300 8 -#define GPO_HP3670 9 -#define GPO_DP665 10 -#define GPO_DP685 11 -#define GPO_CANONLIDE200 12 -#define GPO_KVSS080 13 -#define GPO_G4050 14 -#define GPO_CANONLIDE110 15 -#define GPO_PLUSTEK_3600 16 -#define GPO_CANONLIDE210 17 -#define GPO_HP_N6310 18 -#define GPO_CANONLIDE700 19 -#define GPO_CS4400F 20 -#define GPO_CS8400F 21 -#define GPO_IMG101 22 -#define GPO_PLUSTEK3800 23 -#define GPO_CANONLIDE80 24 -#define GPO_CANONLIDE120 25 - -#define MOTOR_UMAX 0 -#define MOTOR_5345 1 -#define MOTOR_ST24 2 -#define MOTOR_HP2400 3 -#define MOTOR_HP2300 4 -#define MOTOR_CANONLIDE35 5 -#define MOTOR_XP200 6 -#define MOTOR_XP300 7 -#define MOTOR_HP3670 9 -#define MOTOR_DP665 10 -#define MOTOR_ROADWARRIOR 11 -#define MOTOR_DSMOBILE_600 12 -#define MOTOR_CANONLIDE200 13 -#define MOTOR_CANONLIDE100 14 -#define MOTOR_KVSS080 15 -#define MOTOR_G4050 16 -#define MOTOR_CANONLIDE110 17 -#define MOTOR_PLUSTEK_3600 18 -#define MOTOR_CANONLIDE700 19 -#define MOTOR_CS8400F 20 -#define MOTOR_IMG101 21 -#define MOTOR_PLUSTEK3800 22 -#define MOTOR_CANONLIDE210 23 -#define MOTOR_CANONLIDE80 24 -#define MOTOR_CANONLIDE120 25 +enum Genesys_Dac_Type +{ + DAC_WOLFSON_UMAX = 0, + DAC_WOLFSON_ST12, + DAC_WOLFSON_ST24, + DAC_WOLFSON_5345, + DAC_WOLFSON_HP2400, + DAC_WOLFSON_HP2300, + DAC_CANONLIDE35, + DAC_AD_XP200, + DAC_WOLFSON_XP300, + DAC_WOLFSON_HP3670, + DAC_WOLFSON_DSM600, + DAC_CANONLIDE200, + DAC_KVSS080, + DAC_G4050, + DAC_CANONLIDE110, + DAC_PLUSTEK_3600, + DAC_CANONLIDE700, + DAC_CS8400F, + DAC_CS8600F, + DAC_IMG101, + DAC_PLUSTEK3800, + DAC_CANONLIDE80, + DAC_CANONLIDE120 +}; + +enum Genesys_Sensor_Type +{ + CCD_UMAX = 0, + CCD_ST12, // SONY ILX548: 5340 Pixel ??? + CCD_ST24, // SONY ILX569: 10680 Pixel ??? + CCD_5345, + CCD_HP2400, + CCD_HP2300, + CCD_CANONLIDE35, + CIS_XP200, // CIS sensor for Strobe XP200, + CCD_HP3670, + CCD_DP665, + CCD_ROADWARRIOR, + CCD_DSMOBILE600, + CCD_XP300, + CCD_DP685, + CIS_CANONLIDE200, + CIS_CANONLIDE100, + CCD_KVSS080, + CCD_G4050, + CIS_CANONLIDE110, + CCD_PLUSTEK_3600, + CCD_HP_N6310, + CIS_CANONLIDE700, + CCD_CS4400F, + CCD_CS8400F, + CCD_CS8600F, + CCD_IMG101, + CCD_PLUSTEK3800, + CIS_CANONLIDE210, + CIS_CANONLIDE80, + CIS_CANONLIDE220, + CIS_CANONLIDE120, +}; +enum Genesys_Gpo_Type +{ + GPO_UMAX, + GPO_ST12, + GPO_ST24, + GPO_5345, + GPO_HP2400, + GPO_HP2300, + GPO_CANONLIDE35, + GPO_XP200, + GPO_XP300, + GPO_HP3670, + GPO_DP665, + GPO_DP685, + GPO_CANONLIDE200, + GPO_KVSS080, + GPO_G4050, + GPO_CANONLIDE110, + GPO_PLUSTEK_3600, + GPO_CANONLIDE210, + GPO_HP_N6310, + GPO_CANONLIDE700, + GPO_CS4400F, + GPO_CS8400F, + GPO_CS8600F, + GPO_IMG101, + GPO_PLUSTEK3800, + GPO_CANONLIDE80, + GPO_CANONLIDE120 +}; + +enum Genesys_Motor_Type +{ + MOTOR_UMAX = 0, + MOTOR_5345, + MOTOR_ST24, + MOTOR_HP2400, + MOTOR_HP2300, + MOTOR_CANONLIDE35, + MOTOR_XP200, + MOTOR_XP300, + MOTOR_HP3670, + MOTOR_DP665, + MOTOR_ROADWARRIOR, + MOTOR_DSMOBILE_600, + MOTOR_CANONLIDE200, + MOTOR_CANONLIDE100, + MOTOR_KVSS080, + MOTOR_G4050, + MOTOR_CANONLIDE110, + MOTOR_PLUSTEK_3600, + MOTOR_CANONLIDE700, + MOTOR_CS8400F, + MOTOR_CS8600F, + MOTOR_IMG101, + MOTOR_PLUSTEK3800, + MOTOR_CANONLIDE210, + MOTOR_CANONLIDE80, + MOTOR_CANONLIDE120 +}; /* Forward typedefs */ typedef struct Genesys_Device Genesys_Device; @@ -462,15 +1025,21 @@ typedef struct Genesys_Command_Set /*@} */ + bool (*needs_home_before_init_regs_for_scan) (Genesys_Device* dev); + /** For ASIC initialization */ SANE_Status (*init) (Genesys_Device * dev); SANE_Status (*init_regs_for_warmup) (Genesys_Device * dev, + const Genesys_Sensor& sensor, Genesys_Register_Set * regs, int *channels, int *total_size); - SANE_Status (*init_regs_for_coarse_calibration) (Genesys_Device * dev); - SANE_Status (*init_regs_for_shading) (Genesys_Device * dev); - SANE_Status (*init_regs_for_scan) (Genesys_Device * dev); + SANE_Status (*init_regs_for_coarse_calibration) (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set& regs); + SANE_Status (*init_regs_for_shading) (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs); + SANE_Status (*init_regs_for_scan) (Genesys_Device * dev, const Genesys_Sensor& sensor); SANE_Bool (*get_filter_bit) (Genesys_Register_Set * reg); SANE_Bool (*get_lineart_bit) (Genesys_Register_Set * reg); @@ -481,18 +1050,12 @@ typedef struct Genesys_Command_Set SANE_Bool (*test_buffer_empty_bit) (SANE_Byte val); SANE_Bool (*test_motor_flag_bit) (SANE_Byte val); - int (*bulk_full_size) (void); - - SANE_Status (*set_fe) (Genesys_Device * dev, uint8_t set); + SANE_Status (*set_fe) (Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set); SANE_Status (*set_powersaving) (Genesys_Device * dev, int delay); SANE_Status (*save_power) (Genesys_Device * dev, SANE_Bool enable); - void (*set_motor_power) (Genesys_Register_Set * regs, SANE_Bool set); - void (*set_lamp_power) (Genesys_Device * dev, - Genesys_Register_Set * regs, - SANE_Bool set); - SANE_Status (*begin_scan) (Genesys_Device * dev, + const Genesys_Sensor& sensor, Genesys_Register_Set * regs, SANE_Bool start_motor); SANE_Status (*end_scan) (Genesys_Device * dev, @@ -502,32 +1065,31 @@ typedef struct Genesys_Command_Set /** * Send gamma tables to ASIC */ - SANE_Status (*send_gamma_table) (Genesys_Device * dev); + SANE_Status (*send_gamma_table) (Genesys_Device * dev, const Genesys_Sensor& sensor); SANE_Status (*search_start_position) (Genesys_Device * dev); - SANE_Status (*offset_calibration) (Genesys_Device * dev); - SANE_Status (*coarse_gain_calibration) (Genesys_Device * dev, int dpi); - SANE_Status (*led_calibration) (Genesys_Device * dev); - + SANE_Status (*offset_calibration) (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs); + SANE_Status (*coarse_gain_calibration) (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi); + SANE_Status (*led_calibration) (Genesys_Device * dev, Genesys_Sensor& sensor, + Genesys_Register_Set& regs); + + void (*wait_for_motor_stop) (Genesys_Device* dev); SANE_Status (*slow_back_home) (Genesys_Device * dev, SANE_Bool wait_until_home); SANE_Status (*rewind) (Genesys_Device * dev); SANE_Status (*bulk_write_register) (Genesys_Device * dev, - Genesys_Register_Set * reg, - size_t elems); + Genesys_Register_Set& regs); + SANE_Status (*bulk_write_data) (Genesys_Device * dev, uint8_t addr, uint8_t * data, size_t len); SANE_Status (*bulk_read_data) (Genesys_Device * dev, uint8_t addr, uint8_t * data, size_t len); - /* Updates hardware sensor information in Genesys_Scanner.val[]. - If possible, just get information for given option. - The sensor state in Genesys_Scanner.val[] should be merged with the - new sensor state, using the information that was last read by the frontend - in Genesys_Scanner.last_val[], in such a way that a button up/down - relative to Genesys_Scanner.last_val[] is not lost. - */ + // Updates hardware sensor information in Genesys_Scanner.val[]. SANE_Status (*update_hardware_sensors) (struct Genesys_Scanner * s); /* functions for sheetfed scanners */ @@ -548,12 +1110,11 @@ typedef struct Genesys_Command_Set /** * search for an black or white area in forward or reverse * direction */ - SANE_Status (*search_strip) (Genesys_Device * dev, SANE_Bool forward, SANE_Bool black); + SANE_Status (*search_strip) (Genesys_Device * dev, const Genesys_Sensor& sensor, + SANE_Bool forward, SANE_Bool black); - SANE_Status (*is_compatible_calibration) ( - Genesys_Device * dev, - Genesys_Calibration_Cache *cache, - SANE_Bool for_overwrite); + bool (*is_compatible_calibration) (Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Calibration_Cache* cache, SANE_Bool for_overwrite); /* functions for transparency adapter */ /** @@ -564,36 +1125,17 @@ typedef struct Genesys_Command_Set /** * write shading data calibration to ASIC */ - SANE_Status (*send_shading_data) (Genesys_Device * dev, uint8_t * data, int size); + SANE_Status (*send_shading_data) (Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t * data, int size); - /** - * calculate current scan setup - */ - SANE_Status (*calculate_current_setup) (Genesys_Device * dev); + // calculate current scan setup + void (*calculate_current_setup) (Genesys_Device * dev, const Genesys_Sensor& sensor); /** * cold boot init function */ SANE_Status (*asic_boot) (Genesys_Device * dev, SANE_Bool cold); - /** - * Scan register setting interface - */ - SANE_Status (*init_scan_regs) (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres, - float yres, - float startx, - float starty, - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - int scan_method, - int scan_mode, - int color_filter, - unsigned int flags); - } Genesys_Command_Set; /** @brief structure to describe a scanner model @@ -605,6 +1147,7 @@ typedef struct Genesys_Model SANE_String_Const name; SANE_String_Const vendor; SANE_String_Const model; + SANE_Int model_id; SANE_Int asic_type; /* ASIC type gl646 or gl841 */ Genesys_Command_Set *cmd_set; /* pointers to low level functions */ @@ -653,108 +1196,277 @@ typedef struct Genesys_Model SANE_Word buttons; /* Button flags, described existing buttons for the model */ /*@} */ SANE_Int shading_lines; /* how many lines are used for shading calibration */ + SANE_Int shading_ta_lines; // how many lines are used for shading calibration in TA mode SANE_Int search_lines; /* how many lines are used to search start position */ } Genesys_Model; -#define SCAN_METHOD_FLATBED 0 /**< normal scan method */ -#define SCAN_METHOD_TRANSPARENCY 2 /**< scan using transparency adaptor */ -#define SCAN_METHOD_NEGATIVE 0x88 /**< scan using negative adaptor */ +struct Genesys_Settings +{ + ScanMethod scan_method = ScanMethod::FLATBED; + ScanColorMode scan_mode = ScanColorMode::LINEART; -#define SCAN_MODE_LINEART 0 /**< lineart scan mode */ -#define SCAN_MODE_HALFTONE 1 /**< halftone scan mode */ -#define SCAN_MODE_GRAY 2 /**< gray scan mode */ -#define SCAN_MODE_COLOR 4 /**< color scan mode */ + // horizontal dpi + int xres = 0; + // vertical dpi + int yres = 0; -typedef struct -{ - int scan_method; /* todo: change >=2: Transparency, 0x88: negative film */ - int scan_mode; /* todo: change 0,1 = lineart, halftone; 2 = gray, 3 = 3pass color, 4=single pass color */ - int xres; /**< horizontal dpi */ - int yres; /**< vertical dpi */ + //x start on scan table in mm + double tl_x = 0; + // y start on scan table in mm + double tl_y = 0; - double tl_x; /* x start on scan table in mm */ - double tl_y; /* y start on scan table in mm */ + // number of lines at scan resolution + unsigned int lines = 0; + // number of pixels at scan resolution + unsigned int pixels = 0; - unsigned int lines; /**< number of lines at scan resolution */ - unsigned int pixels; /**< number of pixels at scan resolution */ + // bit depth of the scan + unsigned int depth = 0; - unsigned int depth;/* bit depth of the scan */ + ColorFilter color_filter = ColorFilter::NONE; - /* todo : remove these fields ? */ - int exposure_time; + // true if scan is true gray, false if monochrome scan + int true_gray = 0; - unsigned int color_filter; + // lineart threshold + int threshold = 0; - /**< true if scan is true gray, false if monochrome scan */ - int true_gray; + // lineart threshold curve for dynamic rasterization + int threshold_curve = 0; - /**< lineart threshold */ - int threshold; + // Disable interpolation for xres<yres + int disable_interpolation = 0; - /**< lineart threshold curve for dynamic rasterization */ - int threshold_curve; + // true is lineart is generated from gray data by the dynamic rasterization algoright + int dynamic_lineart = 0; - /**< Disable interpolation for xres<yres*/ - int disable_interpolation; + // value for contrast enhancement in the [-100..100] range + int contrast = 0; - /**< Use double x resolution internally to provide better - * quality */ - int double_xres; + // value for brightness enhancement in the [-100..100] range + int brightness = 0; - /**< true is lineart is generated from gray data by - * the dynamic rasterization algo */ - int dynamic_lineart; + // cache entries expiration time + int expiration_time = 0; +}; - /**< value for contrast enhancement in the [-100..100] range */ - int contrast; +struct SetupParams { + + static constexpr unsigned NOT_SET = std::numeric_limits<unsigned>::max(); + + // resolution in x direction + unsigned xres = NOT_SET; + // resolution in y direction + unsigned yres = NOT_SET; + // start pixel in X direction, from dummy_pixel + 1 + float startx = -1; + // start pixel in Y direction, counted according to base_ydpi + float starty = -1; + // the number of pixels in X direction + unsigned pixels = NOT_SET; + // the number of pixels in Y direction + unsigned lines = NOT_SET; + // the depth of the scan in bits. Allowed are 1, 8, 16 + unsigned depth = NOT_SET; + // the number of channels + unsigned channels = NOT_SET; + + ScanMethod scan_method = static_cast<ScanMethod>(NOT_SET); + + ScanColorMode scan_mode = static_cast<ScanColorMode>(NOT_SET); + + ColorFilter color_filter = static_cast<ColorFilter>(NOT_SET); + + unsigned flags = NOT_SET; + + void assert_valid() const + { + if (xres == NOT_SET || yres == NOT_SET || startx < 0 || starty < 0 || + pixels == NOT_SET || lines == NOT_SET ||depth == NOT_SET || channels == NOT_SET || + scan_method == static_cast<ScanMethod>(NOT_SET) || + scan_mode == static_cast<ScanColorMode>(NOT_SET) || + color_filter == static_cast<ColorFilter>(NOT_SET) || + flags == NOT_SET) + { + throw std::runtime_error("SetupParams are not valid"); + } + } + + bool operator==(const SetupParams& other) const + { + return xres == other.xres && + yres == other.yres && + startx == other.startx && + starty == other.starty && + pixels == other.pixels && + lines == other.lines && + depth == other.depth && + channels == other.channels && + scan_method == other.scan_method && + scan_mode == other.scan_mode && + color_filter == other.color_filter && + flags == other.flags; + } +}; - /**< value for brightness enhancement in the [-100..100] range */ - int brightness; - - /**< cahe entries expiration time */ - int expiration_time; -} Genesys_Settings; +template<class Stream> +void serialize(Stream& str, SetupParams& x) +{ + serialize(str, x.xres); + serialize(str, x.yres); + serialize(str, x.startx); + serialize(str, x.starty); + serialize(str, x.pixels); + serialize(str, x.lines); + serialize(str, x.depth); + serialize(str, x.channels); + serialize(str, x.scan_method); + serialize(str, x.scan_mode); + serialize(str, x.color_filter); + serialize(str, x.flags); +} -typedef struct Genesys_Current_Setup +struct Genesys_Current_Setup { - int pixels; /* pixel count expected from scanner */ - int lines; /* line count expected from scanner */ - int depth; /* depth expected from scanner */ - int channels; /* channel count expected from scanner */ - int scan_method; /* scanning method: flatbed or XPA */ - int exposure_time; /* used exposure time */ - float xres; /* used xres */ - float yres; /* used yres*/ - SANE_Bool half_ccd; /* half ccd mode */ - SANE_Int stagger; - SANE_Int max_shift; /* max shift of any ccd component, including staggered pixels*/ -} Genesys_Current_Setup; - -typedef struct Genesys_Buffer + // params used for this setup + SetupParams params; + + // pixel count expected from scanner + int pixels = 0; + // line count expected from scanner + int lines = 0; + // depth expected from scanner + int depth = 0; + // channel count expected from scanner + int channels = 0; + + // used exposure time + int exposure_time = 0; + // used xres + float xres = 0; + // used yres + float yres = 0; + // half ccd mode + unsigned ccd_size_divisor = 1; + SANE_Int stagger = 0; + // max shift of any ccd component, including staggered pixels + SANE_Int max_shift = 0; + + bool operator==(const Genesys_Current_Setup& other) const + { + return params == other.params && + pixels == other.pixels && + lines == other.lines && + depth == other.depth && + channels == other.channels && + exposure_time == other.exposure_time && + xres == other.xres && + yres == other.yres && + ccd_size_divisor == other.ccd_size_divisor && + stagger == other.stagger && + max_shift == other.max_shift; + } +}; + +template<class Stream> +void serialize(Stream& str, Genesys_Current_Setup& x) { - SANE_Byte *buffer; - size_t size; - size_t pos; /* current position in read buffer */ - size_t avail; /* data bytes currently in buffer */ -} Genesys_Buffer; + serialize(str, x.params); + serialize_newline(str); + serialize(str, x.pixels); + serialize(str, x.lines); + serialize(str, x.depth); + serialize(str, x.channels); + serialize(str, x.exposure_time); + serialize(str, x.xres); + serialize(str, x.yres); + serialize(str, x.ccd_size_divisor); + serialize(str, x.stagger); + serialize(str, x.max_shift); +} -struct Genesys_Calibration_Cache +struct Genesys_Buffer { - Genesys_Current_Setup used_setup;/* used to check if entry is compatible */ - time_t last_calibration; + Genesys_Buffer() = default; - Genesys_Frontend frontend; - Genesys_Sensor sensor; + size_t size() const { return buffer_.size(); } + size_t avail() const { return avail_; } + size_t pos() const { return pos_; } - size_t calib_pixels; - size_t calib_channels; - size_t average_size; - uint8_t *white_average_data; - uint8_t *dark_average_data; + // TODO: refactor code that uses this function to no longer use it + void set_pos(size_t pos) { pos_ = pos; } - struct Genesys_Calibration_Cache *next; + void alloc(size_t size); + void clear(); + + void reset(); + + uint8_t* get_write_pos(size_t size); + uint8_t* get_read_pos(); // TODO: mark as const + + void produce(size_t size); + void consume(size_t size); + +private: + std::vector<uint8_t> buffer_; + // current position in read buffer + size_t pos_ = 0; + // data bytes currently in buffer + size_t avail_ = 0; }; +struct Genesys_Calibration_Cache +{ + Genesys_Calibration_Cache() = default; + ~Genesys_Calibration_Cache() = default; + + // used to check if entry is compatible + Genesys_Current_Setup used_setup; + time_t last_calibration = 0; + + Genesys_Frontend frontend; + Genesys_Sensor sensor; + + size_t calib_pixels = 0; + size_t calib_channels = 0; + size_t average_size = 0; + std::vector<uint8_t> white_average_data; + std::vector<uint8_t> dark_average_data; + + bool operator==(const Genesys_Calibration_Cache& other) const + { + return used_setup == other.used_setup && + last_calibration == other.last_calibration && + frontend == other.frontend && + sensor == other.sensor && + calib_pixels == other.calib_pixels && + calib_channels == other.calib_channels && + average_size == other.average_size && + white_average_data == other.white_average_data && + dark_average_data == other.dark_average_data; + } +}; + +template<class Stream> +void serialize(Stream& str, Genesys_Calibration_Cache& x) +{ + serialize(str, x.used_setup); + serialize_newline(str); + serialize(str, x.last_calibration); + serialize_newline(str); + serialize(str, x.frontend); + serialize_newline(str); + serialize(str, x.sensor); + serialize_newline(str); + serialize(str, x.calib_pixels); + serialize(str, x.calib_channels); + serialize(str, x.average_size); + serialize_newline(str); + serialize(str, x.white_average_data); + serialize_newline(str); + serialize(str, x.dark_average_data); +} + /** * Describes the current device status for the backend * session. This should be more accurately called @@ -762,86 +1474,140 @@ struct Genesys_Calibration_Cache */ struct Genesys_Device { - SANE_Int dn; - SANE_Word vendorId; /**< USB vendor identifier */ - SANE_Word productId; /**< USB product identifier */ - SANE_Int usb_mode; /**< USB mode: 1 for USB 1.1, 2 for USB 2.0, - 0 unset and -1 for fake USB device */ - SANE_String file_name; - SANE_String calib_file; - Genesys_Model *model; - - Genesys_Register_Set reg[256]; - Genesys_Register_Set calib_reg[256]; - Genesys_Settings settings; - Genesys_Frontend frontend; - Genesys_Sensor sensor; - Genesys_Gpo gpo; - Genesys_Motor motor; - uint16_t slope_table0[256]; - uint16_t slope_table1[256]; - uint8_t control[6]; - time_t init_date; - - size_t average_size; - size_t calib_pixels; /**< number of pixels used during shading calibration */ - size_t calib_lines; /**< number of lines used during shading calibration */ - size_t calib_channels; - size_t calib_resolution; - uint8_t *white_average_data; - uint8_t *dark_average_data; - uint16_t dark[3]; - - SANE_Bool already_initialized; - SANE_Int scanhead_position_in_steps; - SANE_Int lamp_off_time; - - SANE_Bool read_active; - SANE_Bool parking; /**< signal wether the park command has been issued */ - SANE_Bool document; /**< for sheetfed scanner's, is TRUE when there - is a document in the scanner */ - - Genesys_Buffer read_buffer; - Genesys_Buffer lines_buffer; - Genesys_Buffer shrink_buffer; - Genesys_Buffer out_buffer; - Genesys_Buffer binarize_buffer; /**< buffer for digital lineart from gray data */ - Genesys_Buffer local_buffer; /**< local buffer for gray data during dynamix lineart */ - - size_t read_bytes_left; /**< bytes to read from scanner */ - - size_t total_bytes_read; /**< total bytes read sent to frontend */ - size_t total_bytes_to_read; /**< total bytes read to be sent to frontend */ - size_t wpl; /**< asic's word per line */ - - Genesys_Current_Setup current_setup; /* contains the real used values */ - - /**< look up table used in dynamic rasterization */ - unsigned char lineart_lut[256]; - - Genesys_Calibration_Cache *calibration_cache; - - struct Genesys_Device *next; - - SANE_Int ld_shift_r; /**< used red line-distance shift*/ - SANE_Int ld_shift_g; /**< used green line-distance shift*/ - SANE_Int ld_shift_b; /**< used blue line-distance shift*/ - int segnb; /**< number of segments composing the sensor */ - int line_interp; /**< number of lines used in line interpolation */ - int line_count; /**< number of scan lines used during scan */ - size_t bpl; /**< bytes per full scan widthline */ - size_t dist; /**< bytes distance between an odd and an even pixel */ - size_t len; /**< number of even pixels */ - size_t cur; /**< current pixel position within sub window */ - size_t skip; /**< number of bytes to skip at start of line */ - size_t *order; /**< array describing the order of the sub-segments of the sensor */ - Genesys_Buffer oe_buffer; /**< buffer to handle even/odd data */ - - SANE_Bool buffer_image; /**< when true the scanned picture is first buffered - * to allow software image enhancements */ - SANE_Byte *img_buffer; /**< image buffer where the scanned picture is stored */ - - FILE *binary; /**< binary logger file */ + Genesys_Device() = default; + ~Genesys_Device(); + + using Calibration = std::vector<Genesys_Calibration_Cache>; + + // frees commonly used data + void clear(); + + UsbDevice usb_dev; + SANE_Word vendorId = 0; /**< USB vendor identifier */ + SANE_Word productId = 0; /**< USB product identifier */ + + // USB mode: + // 0: not set + // 1: USB 1.1 + // 2: USB 2.0 + SANE_Int usb_mode = 0; + + SANE_String file_name = nullptr; + std::string calib_file; + + // if enabled, no calibration data will be loaded or saved to files + SANE_Int force_calibration = 0; + Genesys_Model *model = nullptr; + + Genesys_Register_Set reg; + Genesys_Register_Set calib_reg; + Genesys_Settings settings; + Genesys_Frontend frontend, frontend_initial; + Genesys_Gpo gpo; + Genesys_Motor motor; + uint8_t control[6] = {}; + time_t init_date = 0; + + 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; + // 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<uint16_t> gamma_override_tables[3]; + + std::vector<uint8_t> white_average_data; + std::vector<uint8_t> dark_average_data; + uint16_t dark[3] = {}; + + SANE_Bool already_initialized = 0; + SANE_Int scanhead_position_in_steps = 0; + SANE_Int lamp_off_time = 0; + + SANE_Bool read_active = 0; + // signal wether the park command has been issued + SANE_Bool parking = 0; + + // for sheetfed scanner's, is TRUE when there is a document in the scanner + SANE_Bool document = 0; + + SANE_Bool needs_home_ta = 0; + + Genesys_Buffer read_buffer; + Genesys_Buffer lines_buffer; + Genesys_Buffer shrink_buffer; + Genesys_Buffer out_buffer; + + // buffer for digital lineart from gray data + Genesys_Buffer binarize_buffer = {}; + // local buffer for gray data during dynamix lineart + Genesys_Buffer local_buffer = {}; + + // bytes to read from scanner + size_t read_bytes_left = 0; + + // total bytes read sent to frontend + size_t total_bytes_read = 0; + // total bytes read to be sent to frontend + size_t total_bytes_to_read = 0; + // asic's word per line + size_t wpl = 0; + + // contains the real used values + Genesys_Current_Setup current_setup; + + // look up table used in dynamic rasterization + unsigned char lineart_lut[256] = {}; + + Calibration calibration_cache; + + // used red line-distance shift + SANE_Int ld_shift_r = 0; + // used green line-distance shift + SANE_Int ld_shift_g = 0; + // used blue line-distance shift + SANE_Int ld_shift_b = 0; + // number of segments composing the sensor + int segnb = 0; + // number of lines used in line interpolation + int line_interp = 0; + // number of scan lines used during scan + int line_count = 0; + // bytes per full scan widthline + size_t bpl = 0; + // bytes distance between an odd and an even pixel + size_t dist = 0; + // number of even pixels + size_t len = 0; + // current pixel position within sub window + size_t cur = 0; + // number of bytes to skip at start of line + size_t skip = 0; + + // array describing the order of the sub-segments of the sensor + size_t* order = nullptr; + + // buffer to handle even/odd data + Genesys_Buffer oe_buffer = {}; + + // when true the scanned picture is first buffered to allow software image enhancements + SANE_Bool buffer_image = 0; + + // image buffer where the scanned picture is stored + std::vector<uint8_t> img_buffer; + + // binary logger file + FILE *binary = nullptr; }; typedef struct Genesys_USB_Device_Entry @@ -858,7 +1624,7 @@ typedef struct { int motor_type; /**< motor id */ int exposure; /**< exposure for the slope table */ int step_type; /**< default step type for given exposure */ - uint32_t *table; /**< 0 terminated slope table at full step */ + uint32_t *table; // 0-terminated slope table at full step (i.e. step_type == 0) } Motor_Profile; #define FULL_STEP 0 @@ -908,13 +1674,26 @@ typedef struct { /* common functions needed by low level specific functions */ /*--------------------------------------------------------------------------*/ -extern Genesys_Register_Set *sanei_genesys_get_address (Genesys_Register_Set * regs, uint16_t addr); +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 SANE_Byte -sanei_genesys_read_reg_from_set (Genesys_Register_Set * regs, uint16_t address); +inline uint8_t sanei_genesys_read_reg_from_set(Genesys_Register_Set* regs, uint16_t address) +{ + return regs->get8(address); +} -extern void -sanei_genesys_set_reg_from_set (Genesys_Register_Set * regs, uint16_t address, SANE_Byte value); +inline void sanei_genesys_set_reg_from_set(Genesys_Register_Set* regs, uint16_t address, + uint8_t value) +{ + regs->set8(address, value); +} extern SANE_Status sanei_genesys_init_cmd_set (Genesys_Device * dev); @@ -931,25 +1710,38 @@ extern SANE_Status sanei_genesys_write_hregister (Genesys_Device * dev, uint16_t reg, uint8_t val); extern SANE_Status -sanei_genesys_bulk_write_register (Genesys_Device * dev, - Genesys_Register_Set * reg, - size_t elems); +sanei_genesys_bulk_write_register(Genesys_Device * dev, + Genesys_Register_Set& regs); extern SANE_Status sanei_genesys_write_0x8c (Genesys_Device * dev, uint8_t index, uint8_t val); +extern unsigned sanei_genesys_get_bulk_max_size(Genesys_Device * dev); + +extern SANE_Status sanei_genesys_bulk_read_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, + size_t len); + +extern SANE_Status sanei_genesys_bulk_write_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, + size_t len); + extern SANE_Status sanei_genesys_get_status (Genesys_Device * dev, uint8_t * status); extern void sanei_genesys_print_status (uint8_t val); extern SANE_Status -sanei_genesys_write_ahb (SANE_Int dn, int usb_mode, uint32_t addr, uint32_t size, uint8_t * data); - -extern void sanei_genesys_init_fe (Genesys_Device * dev); +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); +Genesys_Sensor& sanei_genesys_find_sensor_any_for_write(Genesys_Device* dev); +const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, int dpi, + ScanMethod scan_method = ScanMethod::FLATBED); +Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, int dpi, + ScanMethod scan_method = ScanMethod::FLATBED); + extern SANE_Status -sanei_genesys_init_shading_data (Genesys_Device * dev, int pixels_per_line); +sanei_genesys_init_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, + int pixels_per_line); extern SANE_Status sanei_genesys_read_valid_words (Genesys_Device * dev, unsigned int *steps); @@ -960,6 +1752,11 @@ extern SANE_Status sanei_genesys_read_scancnt (Genesys_Device * dev, extern SANE_Status sanei_genesys_read_feed_steps (Genesys_Device * dev, unsigned int *steps); +void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, bool set); + +void sanei_genesys_set_motor_power(Genesys_Register_Set& regs, bool set); + extern void sanei_genesys_calculate_zmode2 (SANE_Bool two_table, uint32_t exposure_time, @@ -1026,24 +1823,28 @@ sanei_genesys_create_slope_table3 (Genesys_Device * dev, unsigned int *final_exposure, int power_mode); -extern void -sanei_genesys_create_gamma_table (uint16_t * gamma_table, int size, - float maximum, float gamma_max, - float gamma); +void sanei_genesys_create_default_gamma_table(Genesys_Device* dev, + std::vector<uint16_t>& gamma_table, float gamma); + +std::vector<uint16_t> get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor, + int color); -extern SANE_Status sanei_genesys_send_gamma_table (Genesys_Device * dev); +SANE_Status sanei_genesys_send_gamma_table(Genesys_Device * dev, const Genesys_Sensor& sensor); extern SANE_Status sanei_genesys_start_motor (Genesys_Device * dev); extern SANE_Status sanei_genesys_stop_motor (Genesys_Device * dev); extern SANE_Status -sanei_genesys_search_reference_point (Genesys_Device * dev, uint8_t * data, - int start_pixel, int dpi, int width, - int height); +sanei_genesys_search_reference_point(Genesys_Device * dev, Genesys_Sensor& sensor, + uint8_t * data, + int start_pixel, int dpi, int width, + int height); + +extern SANE_Status sanei_genesys_write_file(const char *filename, uint8_t* data, size_t length); extern SANE_Status -sanei_genesys_write_pnm_file (char *filename, uint8_t * data, int depth, +sanei_genesys_write_pnm_file (const char *filename, uint8_t * data, int depth, int channels, int pixels_per_line, int lines); extern SANE_Status @@ -1053,35 +1854,54 @@ extern SANE_Status sanei_genesys_read_data_from_scanner (Genesys_Device * dev, uint8_t * data, size_t size); -extern SANE_Status -sanei_genesys_buffer_alloc(Genesys_Buffer * buf, size_t size); - -extern SANE_Status -sanei_genesys_buffer_free(Genesys_Buffer * buf); - -extern SANE_Byte * -sanei_genesys_buffer_get_write_pos(Genesys_Buffer * buf, size_t size); - -extern SANE_Byte * -sanei_genesys_buffer_get_read_pos(Genesys_Buffer * buf); +inline void sanei_genesys_set_double(Genesys_Register_Set* regs, uint16_t addr, uint16_t value) +{ + regs->set16(addr, value); +} -extern SANE_Status -sanei_genesys_buffer_produce(Genesys_Buffer * buf, size_t size); +inline void sanei_genesys_set_triple(Genesys_Register_Set* regs, uint16_t addr, uint32_t value) +{ + regs->set24(addr, value); +} -extern SANE_Status -sanei_genesys_buffer_consume(Genesys_Buffer * buf, size_t size); +inline void sanei_genesys_get_double(Genesys_Register_Set* regs, uint16_t addr, uint16_t* value) +{ + *value = regs->get16(addr); +} -extern SANE_Status -sanei_genesys_set_double(Genesys_Register_Set *regs, uint16_t addr, uint16_t value); +inline void sanei_genesys_get_triple(Genesys_Register_Set* regs, uint16_t addr, uint32_t* value) +{ + *value = regs->get24(addr); +} -extern SANE_Status -sanei_genesys_set_triple(Genesys_Register_Set *regs, uint16_t addr, uint32_t value); +inline void sanei_genesys_set_exposure(Genesys_Register_Set& regs, const SensorExposure& exposure) +{ + regs.set8(0x10, (exposure.red >> 8) & 0xff); + regs.set8(0x11, exposure.red & 0xff); + regs.set8(0x12, (exposure.green >> 8) & 0xff); + regs.set8(0x13, exposure.green & 0xff); + regs.set8(0x14, (exposure.blue >> 8) & 0xff); + regs.set8(0x15, exposure.blue & 0xff); +} -extern SANE_Status -sanei_genesys_get_double(Genesys_Register_Set *regs, uint16_t addr, uint16_t *value); +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; +} -extern SANE_Status -sanei_genesys_get_triple(Genesys_Register_Set *regs, uint16_t addr, uint32_t *value); +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); + return exposure; +} extern SANE_Status sanei_genesys_wait_for_home(Genesys_Device *dev); @@ -1089,8 +1909,10 @@ sanei_genesys_wait_for_home(Genesys_Device *dev); extern SANE_Status sanei_genesys_asic_init(Genesys_Device *dev, SANE_Bool cold); -extern -int sanei_genesys_compute_dpihw(Genesys_Device *dev, int xres); +int sanei_genesys_compute_dpihw(Genesys_Device *dev, const Genesys_Sensor& sensor, int xres); + +int sanei_genesys_compute_dpihw_calibration(Genesys_Device *dev, const Genesys_Sensor& sensor, + int xres); extern Motor_Profile *sanei_genesys_get_motor_profile(Motor_Profile *motors, int motor_type, int exposure); @@ -1119,15 +1941,8 @@ int sanei_genesys_get_lowest_ydpi(Genesys_Device *dev); extern int sanei_genesys_get_lowest_dpi(Genesys_Device *dev); -/** - * reads previously cached calibration data - * from file - */ -extern SANE_Status -sanei_genesys_read_calibration (Genesys_Device * dev); - -extern SANE_Status -sanei_genesys_is_compatible_calibration (Genesys_Device * dev, +extern bool +sanei_genesys_is_compatible_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Calibration_Cache * cache, int for_overwrite); @@ -1160,78 +1975,12 @@ sanei_genesys_load_lut (unsigned char * lut, extern SANE_Status sanei_genesys_generate_gamma_buffer(Genesys_Device * dev, + const Genesys_Sensor& sensor, int bits, int max, int size, uint8_t *gamma); -#ifdef UNIT_TESTING -SANE_Status -genesys_send_offset_and_shading (Genesys_Device * dev, - uint8_t * data, - int size); - -void -genesys_average_data (uint8_t * average_data, - uint8_t * calibration_data, - uint32_t lines, - uint32_t pixel_components_per_line); - -void -compute_averaged_planar (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int words_per_color, - unsigned int channels, - unsigned int o, - unsigned int coeff, - unsigned int target_bright, - unsigned int target_dark); - - -void -compute_coefficients (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int channels, - unsigned int cmat[3], - int offset, - unsigned int coeff, - unsigned int target); - -void -compute_planar_coefficients (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int factor, - unsigned int pixels_per_line, - unsigned int words_per_color, - unsigned int channels, - unsigned int cmat[3], - unsigned int offset, - unsigned int coeff, - unsigned int target); - -void -compute_shifted_coefficients (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int channels, - unsigned int cmat[3], - int offset, - unsigned int coeff, - unsigned int target_dark, - unsigned int target_bright, - unsigned int patch_size); /* contigous extent */ - -SANE_Status -probe_genesys_devices (void); - -SANE_Status genesys_flatbed_calibration (Genesys_Device *dev); - -SANE_Status genesys_send_shading_coefficient (Genesys_Device *dev); -#endif - - /*---------------------------------------------------------------------------*/ /* ASIC specific functions declarations */ /*---------------------------------------------------------------------------*/ @@ -1242,4 +1991,52 @@ extern SANE_Status sanei_gl846_init_cmd_set (Genesys_Device * dev); extern SANE_Status sanei_gl847_init_cmd_set (Genesys_Device * dev); extern SANE_Status sanei_gl124_init_cmd_set (Genesys_Device * dev); +// same as usleep, except that it does nothing if testing mode is enabled +extern void sanei_genesys_usleep(unsigned int useconds); + +// same as sanei_genesys_usleep just that the duration is in milliseconds +extern void sanei_genesys_sleep_ms(unsigned int milliseconds); + +void add_function_to_run_at_backend_exit(std::function<void()> function); + +// calls functions added via add_function_to_run_at_backend_exit() in reverse order of being +// added. +void run_functions_at_backend_exit(); + +template<class T> +class StaticInit { +public: + StaticInit() = default; + StaticInit(const StaticInit&) = delete; + StaticInit& operator=(const StaticInit&) = delete; + + template<class... Args> + void init(Args&& ... args) + { + ptr_ = std::unique_ptr<T>(new T(std::forward<Args>(args)...)); + add_function_to_run_at_backend_exit([this](){ deinit(); }); + } + + void deinit() + { + ptr_.release(); + } + + const T* operator->() const { return ptr_.get(); } + T* operator->() { return ptr_.get(); } + const T& operator*() const { return *ptr_.get(); } + T& operator*() { return *ptr_.get(); } + +private: + std::unique_ptr<T> ptr_; +}; + +extern StaticInit<std::vector<Genesys_Sensor>> s_sensors; +void genesys_init_sensor_tables(); +void genesys_init_frontend_tables(); + +void debug_dump(unsigned level, const Genesys_Settings& settings); +void debug_dump(unsigned level, const SetupParams& params); +void debug_dump(unsigned level, const Genesys_Current_Setup& setup); + #endif /* not GENESYS_LOW_H */ |