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