• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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