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