1/* sane - Scanner Access Now Easy.
2
3   Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
4
5   This file is part of the SANE package.
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <https://www.gnu.org/licenses/>.
19*/
20
21#ifndef BACKEND_GENESYS_DEVICE_H
22#define BACKEND_GENESYS_DEVICE_H
23
24#include "calibration.h"
25#include "command_set.h"
26#include "enums.h"
27#include "image_pipeline.h"
28#include "motor.h"
29#include "settings.h"
30#include "sensor.h"
31#include "register.h"
32#include "usb_device.h"
33#include "scanner_interface.h"
34#include "utilities.h"
35#include <vector>
36
37namespace genesys {
38
39struct Genesys_Gpo
40{
41    Genesys_Gpo() = default;
42
43    // Genesys_Gpo
44    GpioId id = GpioId::UNKNOWN;
45
46    /*  GL646 and possibly others:
47        - have the value registers at 0x66 and 0x67
48        - have the enable registers at 0x68 and 0x69
49
50        GL841, GL842, GL843, GL846, GL848 and possibly others:
51        - have the value registers at 0x6c and 0x6d.
52        - have the enable registers at 0x6e and 0x6f.
53    */
54    GenesysRegisterSettingSet regs;
55};
56
57struct MemoryLayout
58{
59    // This is used on GL845, GL846, GL847 and GL124 which have special registers to define the
60    // memory layout
61    MemoryLayout() = default;
62
63    ValueFilter<ModelId> models;
64
65    GenesysRegisterSettingSet regs;
66};
67
68struct MethodResolutions
69{
70    std::vector<ScanMethod> methods;
71    std::vector<unsigned> resolutions_x;
72    std::vector<unsigned> resolutions_y;
73
74    unsigned get_min_resolution_x() const
75    {
76        return *std::min_element(resolutions_x.begin(), resolutions_x.end());
77    }
78
79    unsigned get_nearest_resolution_x(unsigned resolution) const
80    {
81        return *std::min_element(resolutions_x.begin(), resolutions_x.end(),
82                                 [&](unsigned lhs, unsigned rhs)
83        {
84            return std::abs(static_cast<int>(lhs) - static_cast<int>(resolution)) <
85                     std::abs(static_cast<int>(rhs) - static_cast<int>(resolution));
86        });
87    }
88
89    unsigned get_min_resolution_y() const
90    {
91        return *std::min_element(resolutions_y.begin(), resolutions_y.end());
92    }
93
94    std::vector<unsigned> get_resolutions() const;
95};
96
97/** @brief structure to describe a scanner model
98 * This structure describes a model. It is composed of information on the
99 * sensor, the motor, scanner geometry and flags to drive operation.
100 */
101struct Genesys_Model
102{
103    Genesys_Model() = default;
104
105    const char* name = nullptr;
106    const char* vendor = nullptr;
107    const char* model = nullptr;
108    ModelId model_id = ModelId::UNKNOWN;
109
110    AsicType asic_type = AsicType::UNKNOWN;
111
112    // possible x and y resolutions for each method supported by the scanner
113    std::vector<MethodResolutions> resolutions;
114
115    // possible depths in gray mode
116    std::vector<unsigned> bpp_gray_values;
117    // possible depths in color mode
118    std::vector<unsigned> bpp_color_values;
119
120    // the default scanning method. This is used when moving the head for example
121    ScanMethod default_method = ScanMethod::FLATBED;
122
123    // All offsets below are with respect to the sensor home position
124
125    // Start of scan area in mm
126    float x_offset = 0;
127
128    // Start of scan area in mm (Amount of feeding needed to get to the medium)
129    float y_offset = 0;
130
131    // Size of scan area in mm
132    float x_size = 0;
133
134    // Size of scan area in mm
135    float y_size = 0;
136
137    // Start of white strip in mm for scanners that use separate dark and white shading calibration.
138    float y_offset_calib_white = 0;
139
140    // The size of the scan area that is used to acquire shading data in mm
141    float y_size_calib_mm = 0;
142
143    // Start of the black/white strip in mm for scanners that use unified dark and white shading
144    // calibration.
145    float y_offset_calib_dark_white_mm = 0;
146
147    // The size of the scan area that is used to acquire dark/white shading data in mm
148    float y_size_calib_dark_white_mm = 0;
149
150    // The width of the scan area that is used to acquire shading data
151    float x_size_calib_mm = 0;
152
153    // Start of black mark in mm
154    float x_offset_calib_black = 0;
155
156    // Start of scan area in transparency mode in mm
157    float x_offset_ta = 0;
158
159    // Start of scan area in transparency mode in mm
160    float y_offset_ta = 0;
161
162    // Size of scan area in transparency mode in mm
163    float x_size_ta = 0;
164
165    // Size of scan area in transparency mode in mm
166    float y_size_ta = 0;
167
168    // The position of the sensor when it's aligned with the lamp for transparency scanning
169    float y_offset_sensor_to_ta = 0;
170
171    // Start of white strip in transparency mode in mm
172    float y_offset_calib_white_ta = 0;
173
174    // Start of black strip in transparency mode in mm
175    float y_offset_calib_black_ta = 0;
176
177    // The size of the scan area that is used to acquire shading data in transparency mode in mm
178    float y_size_calib_ta_mm = 0;
179
180    // Size of scan area after paper sensor stop sensing document in mm
181    float post_scan = 0;
182
183    // Amount of feeding needed to eject document after finishing scanning in mm
184    float eject_feed = 0;
185
186    // Line-distance correction (in pixel at motor base_ydpi) for CCD scanners
187    SANE_Int ld_shift_r = 0;
188    SANE_Int ld_shift_g = 0;
189    SANE_Int ld_shift_b = 0;
190
191    // Order of the CCD/CIS colors
192    ColorOrder line_mode_color_order = ColorOrder::RGB;
193
194    // Is this a CIS or CCD scanner?
195    bool is_cis = false;
196
197    // Is this sheetfed scanner?
198    bool is_sheetfed = false;
199
200    // sensor type
201    SensorId sensor_id = SensorId::UNKNOWN;
202    // Analog-Digital converter type
203    AdcId adc_id = AdcId::UNKNOWN;
204    // General purpose output type
205    GpioId gpio_id = GpioId::UNKNOWN;
206    // stepper motor type
207    MotorId motor_id = MotorId::UNKNOWN;
208
209    // Which customizations are needed for this scanner?
210    ModelFlag flags = ModelFlag::NONE;
211
212    // Button flags, described existing buttons for the model
213    SANE_Word buttons = 0;
214
215    // how many lines are used to search start position
216    SANE_Int search_lines = 0;
217
218    // returns nullptr if method is not supported
219    const MethodResolutions* get_resolution_settings_ptr(ScanMethod method) const;
220
221    // throws if method is not supported
222    const MethodResolutions& get_resolution_settings(ScanMethod method) const;
223
224    std::vector<unsigned> get_resolutions(ScanMethod method) const;
225
226    bool has_method(ScanMethod method) const;
227};
228
229/**
230 * Describes the current device status for the backend
231 * session. This should be more accurately called
232 * Genesys_Session .
233 */
234struct Genesys_Device
235{
236    Genesys_Device() = default;
237    ~Genesys_Device();
238
239    using Calibration = std::vector<Genesys_Calibration_Cache>;
240
241    // frees commonly used data
242    void clear();
243
244    std::uint16_t vendorId = 0; // USB vendor identifier
245    std::uint16_t productId = 0; // USB product identifier
246
247    // USB mode:
248    // 0: not set
249    // 1: USB 1.1
250    // 2: USB 2.0
251    SANE_Int usb_mode = 0;
252
253    std::string file_name;
254    std::string calib_file;
255
256    // if enabled, no calibration data will be loaded or saved to files
257    SANE_Int force_calibration = 0;
258    // if enabled, will ignore the scan offsets and start scanning at true origin. This allows
259    // acquiring the positions of the black and white strips and the actual scan area
260    bool ignore_offsets = false;
261
262    const Genesys_Model* model = nullptr;
263
264    // pointers to low level functions
265    std::unique_ptr<CommandSet> cmd_set;
266
267    Genesys_Register_Set reg;
268    Genesys_Register_Set initial_regs;
269    Genesys_Settings settings;
270    Genesys_Frontend frontend, frontend_initial;
271    Genesys_Gpo gpo;
272    MemoryLayout memory_layout;
273    Genesys_Motor motor;
274    std::uint8_t control[6] = {};
275
276    size_t average_size = 0;
277
278    // the session that was configured for calibration
279    ScanSession calib_session;
280
281    // gamma overrides. If a respective array is not empty then it means that the gamma for that
282    // color is overridden.
283    std::vector<std::uint16_t> gamma_override_tables[3];
284
285    std::vector<std::uint16_t> white_average_data;
286    std::vector<std::uint16_t> dark_average_data;
287
288    bool already_initialized = false;
289
290    bool read_active = false;
291    // signal whether the park command has been issued
292    bool parking = false;
293
294    // for sheetfed scanner's, is TRUE when there is a document in the scanner
295    bool document = false;
296
297    // total bytes read sent to frontend
298    size_t total_bytes_read = 0;
299    // total bytes read to be sent to frontend
300    size_t total_bytes_to_read = 0;
301
302    // contains computed data for the current setup
303    ScanSession session;
304
305    Calibration calibration_cache;
306
307    // number of scan lines used during scan
308    int line_count = 0;
309
310    // array describing the order of the sub-segments of the sensor
311    std::vector<unsigned> segment_order;
312
313    // stores information about how the input image should be processed
314    ImagePipelineStack pipeline;
315
316    // an buffer that allows reading from `pipeline` in chunks of any size
317    ImageBuffer pipeline_buffer;
318
319    ImagePipelineNodeBufferedCallableSource& get_pipeline_source();
320
321    std::unique_ptr<ScannerInterface> interface;
322
323    bool is_head_pos_known(ScanHeadId scan_head) const;
324    unsigned head_pos(ScanHeadId scan_head) const;
325    void set_head_pos_unknown(ScanHeadId scan_head);
326    void set_head_pos_zero(ScanHeadId scan_head);
327    void advance_head_pos_by_session(ScanHeadId scan_head);
328    void advance_head_pos_by_steps(ScanHeadId scan_head, Direction direction, unsigned steps);
329
330private:
331    // the position of the primary scan head in motor->base_dpi units
332    unsigned head_pos_primary_ = 0;
333    bool is_head_pos_primary_known_ = true;
334
335    // the position of the secondary scan head in motor->base_dpi units. Only certain scanners
336    // have a secondary scan head.
337    unsigned head_pos_secondary_ = 0;
338    bool is_head_pos_secondary_known_ = true;
339
340    friend class ScannerInterfaceUsb;
341};
342
343std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev);
344
345void apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs);
346
347void apply_reg_settings_to_device_write_only(Genesys_Device& dev,
348                                             const GenesysRegisterSettingSet& regs);
349GenesysRegisterSettingSet
350    apply_reg_settings_to_device_with_backup(Genesys_Device& dev,
351                                             const GenesysRegisterSettingSet& regs);
352
353} // namespace genesys
354
355#endif
356