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    As a special exception, the authors of SANE give permission for
21    additional uses of the libraries contained in this release of SANE.
22 
23    The exception is that, if you link a SANE library with other files
24    to produce an executable, this does not by itself cause the
25    resulting executable to be covered by the GNU General Public
26    License.  Your use of that executable is in no way restricted on
27    account of linking the SANE library code into it.
28 
29    This exception does not, however, invalidate any other reasons why
30    the executable file might be covered by the GNU General Public
31    License.
32 
33    If you submit changes to SANE to the maintainers to be included in
34    a subsequent release, you agree by submitting the changes that
35    those changes may be distributed with this exception intact.
36 
37    If you write modifications of your own for SANE, it is your choice
38    whether to permit this exception to apply to your modifications.
39    If you do not wish that, delete this exception notice.
40 */
41 
42 #ifndef BACKEND_GENESYS_SENSOR_H
43 #define BACKEND_GENESYS_SENSOR_H
44 
45 #include "enums.h"
46 #include "register.h"
47 #include "serialize.h"
48 #include "value_filter.h"
49 #include <array>
50 #include <functional>
51 
52 namespace genesys {
53 
54 template<class T, size_t Size>
55 struct AssignableArray : public std::array<T, Size> {
56     AssignableArray() = default;
57     AssignableArray(const AssignableArray&) = default;
58     AssignableArray& operator=(const AssignableArray&) = default;
59 
60     AssignableArray& operator=(std::initializer_list<T> init)
61     {
62         if (init.size() != std::array<T, Size>::size())
63             throw std::runtime_error("An array of incorrect size assigned");
64         std::copy(init.begin(), init.end(), std::array<T, Size>::begin());
65         return *this;
66     }
67 };
68 
69 
70 class StaggerConfig
71 {
72 public:
73     StaggerConfig() = default;
StaggerConfig(std::initializer_list<std::size_t> shifts)74     explicit StaggerConfig(std::initializer_list<std::size_t> shifts) :
75         shifts_{shifts}
76     {
77     }
78 
max_shift()79     std::size_t max_shift() const
80     {
81         if (shifts_.empty()) {
82             return 0;
83         }
84         return *std::max_element(shifts_.begin(), shifts_.end());
85     }
86 
empty()87     bool empty() const { return shifts_.empty(); }
size()88     std::size_t size() const { return shifts_.size(); }
shifts()89     const std::vector<std::size_t>& shifts() const { return shifts_; }
90 
91     bool operator==(const StaggerConfig& other) const
92     {
93         return shifts_ == other.shifts_;
94     }
95 
96 private:
97     std::vector<std::size_t> shifts_;
98 
99     template<class Stream>
100     friend void serialize(Stream& str, StaggerConfig& x);
101 };
102 
103 template<class Stream>
serialize(Stream & str,StaggerConfig & x)104 void serialize(Stream& str, StaggerConfig& x)
105 {
106     serialize(str, x.shifts_);
107 }
108 
109 std::ostream& operator<<(std::ostream& out, const StaggerConfig& config);
110 
111 
112 enum class FrontendType : unsigned
113 {
114     UNKNOWN = 0,
115     WOLFSON,
116     ANALOG_DEVICES,
117     CANON_LIDE_80,
118     WOLFSON_GL841, // old code path, likely wrong calculation
119     WOLFSON_GL846, // old code path, likely wrong calculation
120     ANALOG_DEVICES_GL847, // old code path, likely wrong calculation
121     WOLFSON_GL124, // old code path, likely wrong calculation
122 };
123 
serialize(std::istream & str,FrontendType & x)124 inline void serialize(std::istream& str, FrontendType& x)
125 {
126     unsigned value;
127     serialize(str, value);
128     x = static_cast<FrontendType>(value);
129 }
130 
serialize(std::ostream & str,FrontendType & x)131 inline void serialize(std::ostream& str, FrontendType& x)
132 {
133     unsigned value = static_cast<unsigned>(x);
134     serialize(str, value);
135 }
136 
137 std::ostream& operator<<(std::ostream& out, const FrontendType& type);
138 
139 struct GenesysFrontendLayout
140 {
141     FrontendType type = FrontendType::UNKNOWN;
142     std::array<std::uint16_t, 3> offset_addr = {};
143     std::array<std::uint16_t, 3> gain_addr = {};
144 
145     bool operator==(const GenesysFrontendLayout& other) const
146     {
147         return type == other.type &&
148                 offset_addr == other.offset_addr &&
149                 gain_addr == other.gain_addr;
150     }
151 };
152 
153 template<class Stream>
serialize(Stream & str,GenesysFrontendLayout & x)154 void serialize(Stream& str, GenesysFrontendLayout& x)
155 {
156     serialize(str, x.type);
157     serialize_newline(str);
158     serialize(str, x.offset_addr);
159     serialize_newline(str);
160     serialize(str, x.gain_addr);
161 }
162 
163 std::ostream& operator<<(std::ostream& out, const GenesysFrontendLayout& layout);
164 
165 /** @brief Data structure to set up analog frontend.
166     The analog frontend converts analog value from image sensor to digital value. It has its own
167     control registers which are set up with this structure. The values are written using
168     fe_write_data.
169  */
170 struct Genesys_Frontend
171 {
172     Genesys_Frontend() = default;
173 
174     // id of the frontend description
175     AdcId id = AdcId::UNKNOWN;
176 
177     // all registers of the frontend. Note that the registers can hold 9-bit values
178     RegisterSettingSet<std::uint16_t> regs;
179 
180     // extra control registers
181     std::array<std::uint16_t, 3> reg2 = {};
182 
183     GenesysFrontendLayout layout;
184 
set_offsetGenesys_Frontend185     void set_offset(unsigned which, std::uint16_t value)
186     {
187         regs.set_value(layout.offset_addr[which], value);
188     }
189 
set_gainGenesys_Frontend190     void set_gain(unsigned which, std::uint16_t value)
191     {
192         regs.set_value(layout.gain_addr[which], value);
193     }
194 
get_offsetGenesys_Frontend195     std::uint16_t get_offset(unsigned which) const
196     {
197         return regs.get_value(layout.offset_addr[which]);
198     }
199 
get_gainGenesys_Frontend200     std::uint16_t get_gain(unsigned which) const
201     {
202         return regs.get_value(layout.gain_addr[which]);
203     }
204 
205     bool operator==(const Genesys_Frontend& other) const
206     {
207         return id == other.id &&
208             regs == other.regs &&
209             reg2 == other.reg2 &&
210             layout == other.layout;
211     }
212 };
213 
214 std::ostream& operator<<(std::ostream& out, const Genesys_Frontend& frontend);
215 
216 template<class Stream>
serialize(Stream & str,Genesys_Frontend & x)217 void serialize(Stream& str, Genesys_Frontend& x)
218 {
219     serialize(str, x.id);
220     serialize_newline(str);
221     serialize(str, x.regs);
222     serialize_newline(str);
223     serialize(str, x.reg2);
224     serialize_newline(str);
225     serialize(str, x.layout);
226 }
227 
228 struct SensorExposure {
229     std::uint16_t red = 0;
230     std::uint16_t green = 0;
231     std::uint16_t blue = 0;
232 
233     SensorExposure() = default;
SensorExposureSensorExposure234     SensorExposure(std::uint16_t r, std::uint16_t g, std::uint16_t b) :
235         red{r}, green{g}, blue{b}
236     {}
237 
238     bool operator==(const SensorExposure& other) const
239     {
240         return red == other.red && green == other.green && blue == other.blue;
241     }
242 };
243 
244 std::ostream& operator<<(std::ostream& out, const SensorExposure& exposure);
245 
246 
247 struct Genesys_Sensor {
248 
249     Genesys_Sensor() = default;
250     ~Genesys_Sensor() = default;
251 
252     // id of the sensor description
253     SensorId sensor_id = SensorId::UNKNOWN;
254 
255     // sensor resolution in CCD pixels. Note that we may read more than one CCD pixel per logical
256     // pixel, see ccd_pixels_per_system_pixel()
257     unsigned full_resolution = 0;
258 
259     // sensor resolution in pixel values that are read by the chip. Many scanners make low
260     // resolutions faster by configuring the timings in such a way that 1/2 or 1/4 of pixel values
261     // that are read. If zero, then it is equal to `full_resolution`.
262     unsigned optical_resolution = 0;
263 
264     // the resolution list that the sensor is usable at.
265     ValueFilterAny<unsigned> resolutions = VALUE_FILTER_ANY;
266 
267     // the channel list that the sensor is usable at
268     std::vector<unsigned> channels = { 1, 3 };
269 
270     // the scan method used with the sensor
271     ScanMethod method = ScanMethod::FLATBED;
272 
273     // The scanner may be setup to use a custom dpihw that does not correspond to any actual
274     // resolution. The value zero does not set the override.
275     unsigned register_dpihw = 0;
276 
277     // The scanner may be setup to use a custom dpiset value that does not correspond to any actual
278     // resolution. The value zero does not set the override.
279     unsigned register_dpiset = 0;
280 
281     // The resolution to use for shading calibration
282     unsigned shading_resolution = 0;
283 
284     // How many real pixels correspond to one shading pixel that is sent to the scanner
285     unsigned shading_factor = 1;
286 
287     // How many pixels the shading data is offset to the right from the acquired data. Calculated
288     // in shading resolution.
289     int shading_pixel_offset = 0;
290 
291     // This defines the ratio between logical pixel coordinates and the pixel coordinates sent to
292     // the scanner.
293     Ratio pixel_count_ratio = Ratio{1, 1};
294 
295     // The offset in pixels in terms of scan resolution that needs to be applied to scan position.
296     int output_pixel_offset = 0;
297 
298     int black_pixels = 0;
299     // value of the dummy register
300     int dummy_pixel = 0;
301     // TA CCD target code (reference gain)
302     int fau_gain_white_ref = 0;
303     // CCD target code (reference gain)
304     int gain_white_ref = 0;
305 
306     // red, green and blue initial exposure values
307     SensorExposure exposure;
308 
309     int exposure_lperiod = -1;
310 
311     // the number of pixels in a single segment. This is counted in output resolution.
312     unsigned segment_size = 0;
313 
314     // the order of the segments, if any, for the sensor. If the sensor is not segmented or uses
315     // only single segment, this array can be empty
316     // only on gl843
317     std::vector<unsigned> segment_order;
318 
319     // some CCDs use multiple arrays of pixels for double or quadruple resolution. This can result
320     // in the following effects on the output:
321     //  - every n-th column may be shifted in a vertical direction.
322     //  - the columns themselves may be reordered in arbitrary order and may require shifting
323     //    in X direction.
324     StaggerConfig stagger_x;
325     StaggerConfig stagger_y;
326 
327     // True if calibration should be performed on host-side
328     bool use_host_side_calib = false;
329 
330     GenesysRegisterSettingSet custom_regs;
331     GenesysRegisterSettingSet custom_fe_regs;
332 
333     // red, green and blue gamma coefficient for default gamma tables
334     AssignableArray<float, 3> gamma;
335 
get_optical_resolutionGenesys_Sensor336     unsigned get_optical_resolution() const
337     {
338         if (optical_resolution != 0)
339             return optical_resolution;
340         return full_resolution;
341     }
342 
343     // how many CCD pixels are processed per system pixel time. This corresponds to CKSEL + 1
ccd_pixels_per_system_pixelGenesys_Sensor344     unsigned ccd_pixels_per_system_pixel() const
345     {
346         // same on GL646, GL841, GL843, GL846, GL847, GL124
347         constexpr unsigned REG_CKSEL = 0x03;
348         return (custom_regs.get_value(0x18) & REG_CKSEL) + 1;
349     }
350 
matches_channel_countGenesys_Sensor351     bool matches_channel_count(unsigned count) const
352     {
353         return std::find(channels.begin(), channels.end(), count) != channels.end();
354     }
355 
get_segment_countGenesys_Sensor356     unsigned get_segment_count() const
357     {
358         if (segment_order.size() < 2)
359             return 1;
360         return segment_order.size();
361     }
362 
363     bool operator==(const Genesys_Sensor& other) const
364     {
365         return sensor_id == other.sensor_id &&
366             full_resolution == other.full_resolution &&
367             optical_resolution == other.optical_resolution &&
368             resolutions == other.resolutions &&
369             method == other.method &&
370             shading_resolution == other.shading_resolution &&
371             shading_factor == other.shading_factor &&
372             shading_pixel_offset == other.shading_pixel_offset &&
373             pixel_count_ratio == other.pixel_count_ratio &&
374             output_pixel_offset == other.output_pixel_offset &&
375             black_pixels == other.black_pixels &&
376             dummy_pixel == other.dummy_pixel &&
377             fau_gain_white_ref == other.fau_gain_white_ref &&
378             gain_white_ref == other.gain_white_ref &&
379             exposure == other.exposure &&
380             exposure_lperiod == other.exposure_lperiod &&
381             segment_size == other.segment_size &&
382             segment_order == other.segment_order &&
383             stagger_x == other.stagger_x &&
384             stagger_y == other.stagger_y &&
385             use_host_side_calib == other.use_host_side_calib &&
386             custom_regs == other.custom_regs &&
387             custom_fe_regs == other.custom_fe_regs &&
388             gamma == other.gamma;
389     }
390 };
391 
392 template<class Stream>
serialize(Stream & str,Genesys_Sensor & x)393 void serialize(Stream& str, Genesys_Sensor& x)
394 {
395     serialize(str, x.sensor_id);
396     serialize(str, x.full_resolution);
397     serialize(str, x.resolutions);
398     serialize(str, x.method);
399     serialize(str, x.shading_resolution);
400     serialize(str, x.shading_factor);
401     serialize(str, x.shading_pixel_offset);
402     serialize(str, x.output_pixel_offset);
403     serialize(str, x.pixel_count_ratio);
404     serialize(str, x.black_pixels);
405     serialize(str, x.dummy_pixel);
406     serialize(str, x.fau_gain_white_ref);
407     serialize(str, x.gain_white_ref);
408     serialize_newline(str);
409     serialize(str, x.exposure.blue);
410     serialize(str, x.exposure.green);
411     serialize(str, x.exposure.red);
412     serialize(str, x.exposure_lperiod);
413     serialize_newline(str);
414     serialize(str, x.segment_size);
415     serialize_newline(str);
416     serialize(str, x.segment_order);
417     serialize_newline(str);
418     serialize(str, x.stagger_x);
419     serialize_newline(str);
420     serialize(str, x.stagger_y);
421     serialize_newline(str);
422     serialize(str, x.use_host_side_calib);
423     serialize_newline(str);
424     serialize(str, x.custom_regs);
425     serialize_newline(str);
426     serialize(str, x.custom_fe_regs);
427     serialize_newline(str);
428     serialize(str, x.gamma);
429     serialize_newline(str);
430 }
431 
432 std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor);
433 
434 } // namespace genesys
435 
436 #endif // BACKEND_GENESYS_SENSOR_H
437