sane-project-backends/backend/genesys/device.h

356 wiersze
11 KiB
C++

/* 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, see <https://www.gnu.org/licenses/>.
*/
#ifndef BACKEND_GENESYS_DEVICE_H
#define BACKEND_GENESYS_DEVICE_H
#include "calibration.h"
#include "command_set.h"
#include "enums.h"
#include "image_pipeline.h"
#include "motor.h"
#include "settings.h"
#include "sensor.h"
#include "register.h"
#include "usb_device.h"
#include "scanner_interface.h"
#include "utilities.h"
#include <vector>
namespace genesys {
struct Genesys_Gpo
{
Genesys_Gpo() = default;
// Genesys_Gpo
GpioId id = GpioId::UNKNOWN;
/* GL646 and possibly others:
- have the value registers at 0x66 and 0x67
- have the enable registers at 0x68 and 0x69
GL841, GL842, GL843, GL846, GL848 and possibly others:
- have the value registers at 0x6c and 0x6d.
- have the enable registers at 0x6e and 0x6f.
*/
GenesysRegisterSettingSet regs;
};
struct MemoryLayout
{
// This is used on GL845, GL846, GL847 and GL124 which have special registers to define the
// memory layout
MemoryLayout() = default;
ValueFilter<ModelId> models;
GenesysRegisterSettingSet regs;
};
struct MethodResolutions
{
std::vector<ScanMethod> methods;
std::vector<unsigned> resolutions_x;
std::vector<unsigned> resolutions_y;
unsigned get_min_resolution_x() const
{
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());
}
std::vector<unsigned> get_resolutions() const;
};
/** @brief structure to describe a scanner model
* This structure describes a model. It is composed of information on the
* sensor, the motor, scanner geometry and flags to drive operation.
*/
struct Genesys_Model
{
Genesys_Model() = default;
const char* name = nullptr;
const char* vendor = nullptr;
const char* model = nullptr;
ModelId model_id = ModelId::UNKNOWN;
AsicType asic_type = AsicType::UNKNOWN;
// possible x and y resolutions for each method supported by the scanner
std::vector<MethodResolutions> resolutions;
// possible depths in gray mode
std::vector<unsigned> bpp_gray_values;
// possible depths in color mode
std::vector<unsigned> bpp_color_values;
// the default scanning method. This is used when moving the head for example
ScanMethod default_method = ScanMethod::FLATBED;
// All offsets below are with respect to the sensor home position
// Start of scan area in mm
float x_offset = 0;
// Start of scan area in mm (Amount of feeding needed to get to the medium)
float y_offset = 0;
// Size of scan area in mm
float x_size = 0;
// Size of scan area in mm
float y_size = 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
float x_offset_calib_black = 0;
// Start of scan area in transparency mode in mm
float x_offset_ta = 0;
// Start of scan area in transparency mode in mm
float y_offset_ta = 0;
// Size of scan area in transparency mode in mm
float x_size_ta = 0;
// Size of scan area in transparency mode in mm
float y_size_ta = 0;
// The position of the sensor when it's aligned with the lamp for transparency scanning
float y_offset_sensor_to_ta = 0;
// Start of white strip in transparency mode in mm
float y_offset_calib_white_ta = 0;
// Start of black strip in transparency mode in mm
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
float post_scan = 0;
// Amount of feeding needed to eject document after finishing scanning in mm
float eject_feed = 0;
// 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;
// Order of the CCD/CIS colors
ColorOrder line_mode_color_order = ColorOrder::RGB;
// Is this a CIS or CCD scanner?
bool is_cis = false;
// Is this sheetfed scanner?
bool is_sheetfed = false;
// sensor type
SensorId sensor_id = SensorId::UNKNOWN;
// Analog-Digital converter type
AdcId adc_id = AdcId::UNKNOWN;
// General purpose output type
GpioId gpio_id = GpioId::UNKNOWN;
// stepper motor type
MotorId motor_id = MotorId::UNKNOWN;
// 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 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;
};
/**
* Describes the current device status for the backend
* session. This should be more accurately called
* Genesys_Session .
*/
struct Genesys_Device
{
Genesys_Device() = default;
~Genesys_Device();
using Calibration = std::vector<Genesys_Calibration_Cache>;
// frees commonly used data
void clear();
std::uint16_t vendorId = 0; // USB vendor identifier
std::uint16_t productId = 0; // USB product identifier
// USB mode:
// 0: not set
// 1: USB 1.1
// 2: USB 2.0
SANE_Int usb_mode = 0;
std::string file_name;
std::string calib_file;
// if enabled, no calibration data will be loaded or saved to files
SANE_Int force_calibration = 0;
// if enabled, will ignore the scan offsets and start scanning at true origin. This allows
// acquiring the positions of the black and white strips and the actual scan area
bool ignore_offsets = false;
const Genesys_Model* model = nullptr;
// pointers to low level functions
std::unique_ptr<CommandSet> cmd_set;
Genesys_Register_Set reg;
Genesys_Register_Set initial_regs;
Genesys_Settings settings;
Genesys_Frontend frontend, frontend_initial;
Genesys_Gpo gpo;
MemoryLayout memory_layout;
Genesys_Motor motor;
std::uint8_t control[6] = {};
size_t average_size = 0;
// the session that was configured for calibration
ScanSession calib_session;
// 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];
std::vector<std::uint16_t> white_average_data;
std::vector<std::uint16_t> dark_average_data;
bool already_initialized = false;
bool read_active = false;
// signal whether the park command has been issued
bool parking = false;
// for sheetfed scanner's, is TRUE when there is a document in the scanner
bool document = false;
// 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;
// contains computed data for the current setup
ScanSession session;
Calibration calibration_cache;
// number of scan lines used during scan
int line_count = 0;
// array describing the order of the sub-segments of the sensor
std::vector<unsigned> segment_order;
// 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;
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(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);
private:
// the position of the primary scan head in motor->base_dpi units
unsigned head_pos_primary_ = 0;
bool is_head_pos_primary_known_ = true;
// the position of the secondary scan head in motor->base_dpi units. Only certain scanners
// have a secondary scan head.
unsigned head_pos_secondary_ = 0;
bool is_head_pos_secondary_known_ = true;
friend class ScannerInterfaceUsb;
};
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