1 /* sane - Scanner Access Now Easy.
2
3 Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr>
4
5
6 This file is part of the SANE package.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <https://www.gnu.org/licenses/>.
20
21 As a special exception, the authors of SANE give permission for
22 additional uses of the libraries contained in this release of SANE.
23
24 The exception is that, if you link a SANE library with other files
25 to produce an executable, this does not by itself cause the
26 resulting executable to be covered by the GNU General Public
27 License. Your use of that executable is in no way restricted on
28 account of linking the SANE library code into it.
29
30 This exception does not, however, invalidate any other reasons why
31 the executable file might be covered by the GNU General Public
32 License.
33
34 If you submit changes to SANE to the maintainers to be included in
35 a subsequent release, you agree by submitting the changes that
36 those changes may be distributed with this exception intact.
37
38 If you write modifications of your own for SANE, it is your choice
39 whether to permit this exception to apply to your modifications.
40 If you do not wish that, delete this exception notice.
41 */
42
43 #define DEBUG_DECLARE_ONLY
44
45 #include "low.h"
46 #include "assert.h"
47 #include "test_settings.h"
48
49 #include "gl124_registers.h"
50 #include "gl646_registers.h"
51 #include "gl841_registers.h"
52 #include "gl842_registers.h"
53 #include "gl843_registers.h"
54 #include "gl846_registers.h"
55 #include "gl847_registers.h"
56 #include "gl646_registers.h"
57
58 #include "gl124.h"
59 #include "gl646.h"
60 #include "gl841.h"
61 #include "gl842.h"
62 #include "gl843.h"
63 #include "gl846.h"
64 #include "gl847.h"
65 #include "gl646.h"
66
67 #include <cstdio>
68 #include <chrono>
69 #include <cmath>
70 #include <vector>
71
72 /* ------------------------------------------------------------------------ */
73 /* functions calling ASIC specific functions */
74 /* ------------------------------------------------------------------------ */
75
76 namespace genesys {
77
create_cmd_set(AsicType asic_type)78 std::unique_ptr<CommandSet> create_cmd_set(AsicType asic_type)
79 {
80 switch (asic_type) {
81 case AsicType::GL646: return std::unique_ptr<CommandSet>(new gl646::CommandSetGl646{});
82 case AsicType::GL841: return std::unique_ptr<CommandSet>(new gl841::CommandSetGl841{});
83 case AsicType::GL842: return std::unique_ptr<CommandSet>(new gl842::CommandSetGl842{});
84 case AsicType::GL843: return std::unique_ptr<CommandSet>(new gl843::CommandSetGl843{});
85 case AsicType::GL845: // since only a few reg bits differs we handle both together
86 case AsicType::GL846: return std::unique_ptr<CommandSet>(new gl846::CommandSetGl846{});
87 case AsicType::GL847: return std::unique_ptr<CommandSet>(new gl847::CommandSetGl847{});
88 case AsicType::GL124: return std::unique_ptr<CommandSet>(new gl124::CommandSetGl124{});
89 default: throw SaneException(SANE_STATUS_INVAL, "unknown ASIC type");
90 }
91 }
92
93 /* ------------------------------------------------------------------------ */
94 /* General IO and debugging functions */
95 /* ------------------------------------------------------------------------ */
96
sanei_genesys_write_file(const char * filename,const std::uint8_t * data,std::size_t length)97 void sanei_genesys_write_file(const char* filename, const std::uint8_t* data, std::size_t length)
98 {
99 DBG_HELPER(dbg);
100 std::FILE* out = std::fopen(filename, "w");
101 if (!out) {
102 throw SaneException("could not open %s for writing: %s", filename, strerror(errno));
103 }
104 std::fwrite(data, 1, length, out);
105 std::fclose(out);
106 }
107
108 /* ------------------------------------------------------------------------ */
109 /* Read and write RAM, registers and AFE */
110 /* ------------------------------------------------------------------------ */
111
sanei_genesys_get_bulk_max_size(AsicType asic_type)112 unsigned sanei_genesys_get_bulk_max_size(AsicType asic_type)
113 {
114 /* Genesys supports 0xFE00 maximum size in general, wheraus GL646 supports
115 0xFFC0. We use 0xF000 because that's the packet limit in the Linux usbmon
116 USB capture stack. By default it limits packet size to b_size / 5 where
117 b_size is the size of the ring buffer. By default it's 300*1024, so the
118 packet is limited 61440 without any visibility to acquiring software.
119 */
120 if (asic_type == AsicType::GL124 ||
121 asic_type == AsicType::GL846 ||
122 asic_type == AsicType::GL847)
123 {
124 return 0xeff0;
125 }
126 return 0xf000;
127 }
128
129 // Set address for writing data
sanei_genesys_set_buffer_address(Genesys_Device * dev,uint32_t addr)130 void sanei_genesys_set_buffer_address(Genesys_Device* dev, uint32_t addr)
131 {
132 DBG_HELPER(dbg);
133
134 if (dev->model->asic_type==AsicType::GL847 ||
135 dev->model->asic_type==AsicType::GL845 ||
136 dev->model->asic_type==AsicType::GL846 ||
137 dev->model->asic_type==AsicType::GL124)
138 {
139 DBG(DBG_warn, "%s: shouldn't be used for GL846+ ASICs\n", __func__);
140 return;
141 }
142
143 DBG(DBG_io, "%s: setting address to 0x%05x\n", __func__, addr & 0xfffffff0);
144
145 addr = addr >> 4;
146
147 dev->interface->write_register(0x2b, (addr & 0xff));
148
149 addr = addr >> 8;
150 dev->interface->write_register(0x2a, (addr & 0xff));
151 }
152
153 /* ------------------------------------------------------------------------ */
154 /* Medium level functions */
155 /* ------------------------------------------------------------------------ */
156
scanner_read_status(Genesys_Device & dev)157 Status scanner_read_status(Genesys_Device& dev)
158 {
159 DBG_HELPER(dbg);
160 std::uint16_t address = 0;
161
162 switch (dev.model->asic_type) {
163 case AsicType::GL124: address = 0x101; break;
164 case AsicType::GL646:
165 case AsicType::GL841:
166 case AsicType::GL842:
167 case AsicType::GL843:
168 case AsicType::GL845:
169 case AsicType::GL846:
170 case AsicType::GL847: address = 0x41; break;
171 default: throw SaneException("Unsupported asic type");
172 }
173
174 // same for all chips
175 constexpr std::uint8_t PWRBIT = 0x80;
176 constexpr std::uint8_t BUFEMPTY = 0x40;
177 constexpr std::uint8_t FEEDFSH = 0x20;
178 constexpr std::uint8_t SCANFSH = 0x10;
179 constexpr std::uint8_t HOMESNR = 0x08;
180 constexpr std::uint8_t LAMPSTS = 0x04;
181 constexpr std::uint8_t FEBUSY = 0x02;
182 constexpr std::uint8_t MOTORENB = 0x01;
183
184 auto value = dev.interface->read_register(address);
185 Status status;
186 status.is_replugged = !(value & PWRBIT);
187 status.is_buffer_empty = value & BUFEMPTY;
188 status.is_feeding_finished = value & FEEDFSH;
189 status.is_scanning_finished = value & SCANFSH;
190 status.is_at_home = value & HOMESNR;
191 status.is_lamp_on = value & LAMPSTS;
192 status.is_front_end_busy = value & FEBUSY;
193 status.is_motor_enabled = value & MOTORENB;
194
195 if (DBG_LEVEL >= DBG_io) {
196 debug_print_status(dbg, status);
197 }
198
199 return status;
200 }
201
scanner_read_reliable_status(Genesys_Device & dev)202 Status scanner_read_reliable_status(Genesys_Device& dev)
203 {
204 DBG_HELPER(dbg);
205
206 scanner_read_status(dev);
207 dev.interface->sleep_ms(100);
208 return scanner_read_status(dev);
209 }
210
scanner_read_print_status(Genesys_Device & dev)211 void scanner_read_print_status(Genesys_Device& dev)
212 {
213 scanner_read_status(dev);
214 }
215
216 /**
217 * decodes and prints content of status register
218 * @param val value read from status register
219 */
debug_print_status(DebugMessageHelper & dbg,Status val)220 void debug_print_status(DebugMessageHelper& dbg, Status val)
221 {
222 std::stringstream str;
223 str << val;
224 dbg.vlog(DBG_info, "status=%s\n", str.str().c_str());
225 }
226
scanner_register_rw_clear_bits(Genesys_Device & dev,std::uint16_t address,std::uint8_t mask)227 void scanner_register_rw_clear_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask)
228 {
229 scanner_register_rw_bits(dev, address, 0x00, mask);
230 }
231
scanner_register_rw_set_bits(Genesys_Device & dev,std::uint16_t address,std::uint8_t mask)232 void scanner_register_rw_set_bits(Genesys_Device& dev, std::uint16_t address, std::uint8_t mask)
233 {
234 scanner_register_rw_bits(dev, address, mask, mask);
235 }
236
scanner_register_rw_bits(Genesys_Device & dev,std::uint16_t address,std::uint8_t value,std::uint8_t mask)237 void scanner_register_rw_bits(Genesys_Device& dev, std::uint16_t address,
238 std::uint8_t value, std::uint8_t mask)
239 {
240 auto reg_value = dev.interface->read_register(address);
241 reg_value = (reg_value & ~mask) | (value & mask);
242 dev.interface->write_register(address, reg_value);
243 }
244
245 /** read the number of valid words in scanner's RAM
246 * ie registers 42-43-44
247 */
248 // candidate for moving into chip specific files?
sanei_genesys_read_valid_words(Genesys_Device * dev,unsigned int * words)249 void sanei_genesys_read_valid_words(Genesys_Device* dev, unsigned int* words)
250 {
251 DBG_HELPER(dbg);
252
253 switch (dev->model->asic_type)
254 {
255 case AsicType::GL124:
256 *words = dev->interface->read_register(0x102) & 0x03;
257 *words = *words * 256 + dev->interface->read_register(0x103);
258 *words = *words * 256 + dev->interface->read_register(0x104);
259 *words = *words * 256 + dev->interface->read_register(0x105);
260 break;
261
262 case AsicType::GL845:
263 case AsicType::GL846:
264 *words = dev->interface->read_register(0x42) & 0x02;
265 *words = *words * 256 + dev->interface->read_register(0x43);
266 *words = *words * 256 + dev->interface->read_register(0x44);
267 *words = *words * 256 + dev->interface->read_register(0x45);
268 break;
269
270 case AsicType::GL847:
271 *words = dev->interface->read_register(0x42) & 0x03;
272 *words = *words * 256 + dev->interface->read_register(0x43);
273 *words = *words * 256 + dev->interface->read_register(0x44);
274 *words = *words * 256 + dev->interface->read_register(0x45);
275 break;
276
277 default:
278 *words = dev->interface->read_register(0x44);
279 *words += dev->interface->read_register(0x43) * 256;
280 if (dev->model->asic_type == AsicType::GL646) {
281 *words += ((dev->interface->read_register(0x42) & 0x03) * 256 * 256);
282 } else {
283 *words += ((dev->interface->read_register(0x42) & 0x0f) * 256 * 256);
284 }
285 }
286
287 DBG(DBG_proc, "%s: %d words\n", __func__, *words);
288 }
289
290 /** read the number of lines scanned
291 * ie registers 4b-4c-4d
292 */
sanei_genesys_read_scancnt(Genesys_Device * dev,unsigned int * words)293 void sanei_genesys_read_scancnt(Genesys_Device* dev, unsigned int* words)
294 {
295 DBG_HELPER(dbg);
296
297 if (dev->model->asic_type == AsicType::GL124) {
298 *words = (dev->interface->read_register(0x10b) & 0x0f) << 16;
299 *words += (dev->interface->read_register(0x10c) << 8);
300 *words += dev->interface->read_register(0x10d);
301 }
302 else
303 {
304 *words = dev->interface->read_register(0x4d);
305 *words += dev->interface->read_register(0x4c) * 256;
306 if (dev->model->asic_type == AsicType::GL646) {
307 *words += ((dev->interface->read_register(0x4b) & 0x03) * 256 * 256);
308 } else {
309 *words += ((dev->interface->read_register(0x4b) & 0x0f) * 256 * 256);
310 }
311 }
312
313 DBG(DBG_proc, "%s: %d lines\n", __func__, *words);
314 }
315
316 /** @brief Check if the scanner's internal data buffer is empty
317 * @param *dev device to test for data
318 * @param *empty return value
319 * @return empty will be set to true if there is no scanned data.
320 **/
sanei_genesys_is_buffer_empty(Genesys_Device * dev)321 bool sanei_genesys_is_buffer_empty(Genesys_Device* dev)
322 {
323 DBG_HELPER(dbg);
324
325 dev->interface->sleep_ms(1);
326
327 auto status = scanner_read_status(*dev);
328
329 if (status.is_buffer_empty) {
330 /* fix timing issue on USB3 (or just may be too fast) hardware
331 * spotted by John S. Weber <jweber53@gmail.com>
332 */
333 dev->interface->sleep_ms(1);
334 DBG(DBG_io2, "%s: buffer is empty\n", __func__);
335 return true;
336 }
337
338
339 DBG(DBG_io, "%s: buffer is filled\n", __func__);
340 return false;
341 }
342
wait_until_buffer_non_empty(Genesys_Device * dev,bool check_status_twice)343 void wait_until_buffer_non_empty(Genesys_Device* dev, bool check_status_twice)
344 {
345 // FIXME: reduce MAX_RETRIES once tests are updated
346 const unsigned MAX_RETRIES = 100000;
347 for (unsigned i = 0; i < MAX_RETRIES; ++i) {
348
349 if (check_status_twice) {
350 // FIXME: this only to preserve previous behavior, can be removed
351 scanner_read_status(*dev);
352 }
353
354 bool empty = sanei_genesys_is_buffer_empty(dev);
355 dev->interface->sleep_ms(10);
356 if (!empty)
357 return;
358 }
359 throw SaneException(SANE_STATUS_IO_ERROR, "failed to read data");
360 }
361
wait_until_has_valid_words(Genesys_Device * dev)362 void wait_until_has_valid_words(Genesys_Device* dev)
363 {
364 unsigned words = 0;
365 unsigned sleep_time_ms = 10;
366
367 for (unsigned wait_ms = 0; wait_ms < 70000; wait_ms += sleep_time_ms) {
368 sanei_genesys_read_valid_words(dev, &words);
369 if (words != 0)
370 break;
371 dev->interface->sleep_ms(sleep_time_ms);
372 }
373
374 if (words == 0) {
375 throw SaneException(SANE_STATUS_IO_ERROR, "timeout, buffer does not get filled");
376 }
377 }
378
379 // Read data (e.g scanned image) from scan buffer
sanei_genesys_read_data_from_scanner(Genesys_Device * dev,uint8_t * data,size_t size)380 void sanei_genesys_read_data_from_scanner(Genesys_Device* dev, uint8_t* data, size_t size)
381 {
382 DBG_HELPER_ARGS(dbg, "size = %zu bytes", size);
383
384 if (size & 1)
385 DBG(DBG_info, "WARNING %s: odd number of bytes\n", __func__);
386
387 wait_until_has_valid_words(dev);
388
389 dev->interface->bulk_read_data(0x45, data, size);
390 }
391
read_unshuffled_image_from_scanner(Genesys_Device * dev,const ScanSession & session,std::size_t total_bytes)392 Image read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession& session,
393 std::size_t total_bytes)
394 {
395 DBG_HELPER(dbg);
396
397 auto format = create_pixel_format(session.params.depth,
398 dev->model->is_cis ? 1 : session.params.channels,
399 dev->model->line_mode_color_order);
400
401 auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw);
402 auto height = session.optical_line_count;
403
404 Image image(width, height, format);
405
406 auto max_bytes = image.get_row_bytes() * height;
407 if (total_bytes > max_bytes) {
408 throw SaneException("Trying to read too much data %zu (max %zu)", total_bytes, max_bytes);
409 }
410 if (total_bytes != max_bytes) {
411 DBG(DBG_info, "WARNING %s: trying to read not enough data (%zu, full fill %zu)\n", __func__,
412 total_bytes, max_bytes);
413 }
414
415 sanei_genesys_read_data_from_scanner(dev, image.get_row_ptr(0), total_bytes);
416
417 ImagePipelineStack pipeline;
418 pipeline.push_first_node<ImagePipelineNodeImageSource>(image);
419
420 if (session.segment_count > 1) {
421 auto output_width = session.output_segment_pixel_group_count * session.segment_count;
422 pipeline.push_node<ImagePipelineNodeDesegment>(output_width, dev->segment_order,
423 session.conseq_pixel_dist,
424 1, 1);
425 }
426
427 if (session.params.depth == 16) {
428 unsigned num_swaps = 0;
429 if (has_flag(dev->model->flags, ModelFlag::SWAP_16BIT_DATA)) {
430 num_swaps++;
431 }
432 #ifdef WORDS_BIGENDIAN
433 num_swaps++;
434 #endif
435 if (num_swaps % 2 != 0) {
436 dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
437 }
438 }
439
440 if (has_flag(dev->model->flags, ModelFlag::INVERT_PIXEL_DATA)) {
441 pipeline.push_node<ImagePipelineNodeInvert>();
442 }
443
444 if (dev->model->is_cis && session.params.channels == 3) {
445 pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev->model->line_mode_color_order);
446 }
447
448 if (pipeline.get_output_format() == PixelFormat::BGR888) {
449 pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
450 }
451
452 if (pipeline.get_output_format() == PixelFormat::BGR161616) {
453 pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
454 }
455
456 return pipeline.get_image();
457 }
458
459
read_shuffled_image_from_scanner(Genesys_Device * dev,const ScanSession & session)460 Image read_shuffled_image_from_scanner(Genesys_Device* dev, const ScanSession& session)
461 {
462 DBG_HELPER(dbg);
463
464 std::size_t total_bytes = 0;
465 std::size_t pixels_per_line = 0;
466
467 if (dev->model->asic_type == AsicType::GL842 ||
468 dev->model->asic_type == AsicType::GL843 ||
469 dev->model->model_id == ModelId::CANON_5600F)
470 {
471 pixels_per_line = session.output_pixels;
472 } else {
473 // BUG: this selects incorrect pixel number
474 pixels_per_line = session.params.pixels;
475 }
476
477 // FIXME: the current calculation is likely incorrect on non-GL843 implementations,
478 // but this needs checking. Note the extra line when computing size.
479 if (dev->model->asic_type == AsicType::GL842 ||
480 dev->model->asic_type == AsicType::GL843 ||
481 dev->model->model_id == ModelId::CANON_5600F)
482 {
483 total_bytes = session.output_total_bytes_raw;
484 } else {
485 total_bytes = session.params.channels * 2 * pixels_per_line * (session.params.lines + 1);
486 }
487
488 auto format = create_pixel_format(session.params.depth,
489 dev->model->is_cis ? 1 : session.params.channels,
490 dev->model->line_mode_color_order);
491
492 // auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw);
493 auto width = pixels_per_line;
494 auto height = session.params.lines + 1; // BUG: incorrect
495 if (dev->model->asic_type == AsicType::GL842 ||
496 dev->model->asic_type == AsicType::GL843 ||
497 dev->model->model_id == ModelId::CANON_5600F)
498 {
499 height = session.optical_line_count;
500 }
501
502 Image image(width, height, format);
503
504 auto max_bytes = image.get_row_bytes() * height;
505 if (total_bytes > max_bytes) {
506 throw SaneException("Trying to read too much data %zu (max %zu)", total_bytes, max_bytes);
507 }
508 if (total_bytes != max_bytes) {
509 DBG(DBG_info, "WARNING %s: trying to read not enough data (%zu, full fill %zu)\n", __func__,
510 total_bytes, max_bytes);
511 }
512
513 sanei_genesys_read_data_from_scanner(dev, image.get_row_ptr(0), total_bytes);
514
515 ImagePipelineStack pipeline;
516 pipeline.push_first_node<ImagePipelineNodeImageSource>(image);
517
518 if (session.segment_count > 1) {
519 auto output_width = session.output_segment_pixel_group_count * session.segment_count;
520 pipeline.push_node<ImagePipelineNodeDesegment>(output_width, dev->segment_order,
521 session.conseq_pixel_dist,
522 1, 1);
523 }
524
525 if (session.params.depth == 16) {
526 unsigned num_swaps = 0;
527 if (has_flag(dev->model->flags, ModelFlag::SWAP_16BIT_DATA)) {
528 num_swaps++;
529 }
530 #ifdef WORDS_BIGENDIAN
531 num_swaps++;
532 #endif
533 if (num_swaps % 2 != 0) {
534 dev->pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
535 }
536 }
537
538 if (has_flag(dev->model->flags, ModelFlag::INVERT_PIXEL_DATA)) {
539 pipeline.push_node<ImagePipelineNodeInvert>();
540 }
541
542 if (dev->model->is_cis && session.params.channels == 3) {
543 pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev->model->line_mode_color_order);
544 }
545
546 if (pipeline.get_output_format() == PixelFormat::BGR888) {
547 pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
548 }
549
550 if (pipeline.get_output_format() == PixelFormat::BGR161616) {
551 pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
552 }
553
554 return pipeline.get_image();
555 }
556
sanei_genesys_read_feed_steps(Genesys_Device * dev,unsigned int * steps)557 void sanei_genesys_read_feed_steps(Genesys_Device* dev, unsigned int* steps)
558 {
559 DBG_HELPER(dbg);
560
561 if (dev->model->asic_type == AsicType::GL124) {
562 *steps = (dev->interface->read_register(0x108) & 0x1f) << 16;
563 *steps += (dev->interface->read_register(0x109) << 8);
564 *steps += dev->interface->read_register(0x10a);
565 }
566 else
567 {
568 *steps = dev->interface->read_register(0x4a);
569 *steps += dev->interface->read_register(0x49) * 256;
570 if (dev->model->asic_type == AsicType::GL646) {
571 *steps += ((dev->interface->read_register(0x48) & 0x03) * 256 * 256);
572 } else if (dev->model->asic_type == AsicType::GL841) {
573 *steps += ((dev->interface->read_register(0x48) & 0x0f) * 256 * 256);
574 } else {
575 *steps += ((dev->interface->read_register(0x48) & 0x1f) * 256 * 256);
576 }
577 }
578
579 DBG(DBG_proc, "%s: %d steps\n", __func__, *steps);
580 }
581
sanei_genesys_set_lamp_power(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs,bool set)582 void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sensor,
583 Genesys_Register_Set& regs, bool set)
584 {
585 static const uint8_t REG_0x03_LAMPPWR = 0x10;
586
587 if (set) {
588 regs.find_reg(0x03).value |= REG_0x03_LAMPPWR;
589
590 if (dev->model->asic_type == AsicType::GL841) {
591 regs_set_exposure(dev->model->asic_type, regs,
592 sanei_genesys_fixup_exposure(sensor.exposure));
593 regs.set8(0x19, 0x50);
594 }
595
596 if (dev->model->asic_type == AsicType::GL843) {
597 regs_set_exposure(dev->model->asic_type, regs, sensor.exposure);
598 }
599
600 // we don't actually turn on lamp on infrared scan
601 if ((dev->model->model_id == ModelId::CANON_8400F ||
602 dev->model->model_id == ModelId::CANON_8600F ||
603 dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
604 dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I ||
605 dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I) &&
606 dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
607 {
608 regs.find_reg(0x03).value &= ~REG_0x03_LAMPPWR;
609 }
610 } else {
611 regs.find_reg(0x03).value &= ~REG_0x03_LAMPPWR;
612
613 if (dev->model->asic_type == AsicType::GL841) {
614 regs_set_exposure(dev->model->asic_type, regs, sanei_genesys_fixup_exposure({0, 0, 0}));
615 regs.set8(0x19, 0xff);
616 }
617 if (dev->model->model_id == ModelId::CANON_5600F) {
618 regs_set_exposure(dev->model->asic_type, regs, sanei_genesys_fixup_exposure({0, 0, 0}));
619 }
620 }
621 regs.state.is_lamp_on = set;
622 }
623
sanei_genesys_set_motor_power(Genesys_Register_Set & regs,bool set)624 void sanei_genesys_set_motor_power(Genesys_Register_Set& regs, bool set)
625 {
626 static const uint8_t REG_0x02_MTRPWR = 0x10;
627
628 if (set) {
629 regs.find_reg(0x02).value |= REG_0x02_MTRPWR;
630 } else {
631 regs.find_reg(0x02).value &= ~REG_0x02_MTRPWR;
632 }
633 regs.state.is_motor_on = set;
634 }
635
should_enable_gamma(const ScanSession & session,const Genesys_Sensor & sensor)636 bool should_enable_gamma(const ScanSession& session, const Genesys_Sensor& sensor)
637 {
638 if ((session.params.flags & ScanFlag::DISABLE_GAMMA) != ScanFlag::NONE) {
639 return false;
640 }
641 if (sensor.gamma[0] == 1.0f || sensor.gamma[1] == 1.0f || sensor.gamma[2] == 1.0f) {
642 return false;
643 }
644 if (session.params.depth == 16)
645 return false;
646
647 return true;
648 }
649
get_gamma_table(Genesys_Device * dev,const Genesys_Sensor & sensor,int color)650 std::vector<uint16_t> get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor,
651 int color)
652 {
653 if (!dev->gamma_override_tables[color].empty()) {
654 return dev->gamma_override_tables[color];
655 } else {
656 std::vector<uint16_t> ret;
657 sanei_genesys_create_default_gamma_table(dev, ret, sensor.gamma[color]);
658 return ret;
659 }
660 }
661
662 /** @brief generates gamma buffer to transfer
663 * Generates gamma table buffer to send to ASIC. Applies
664 * contrast and brightness if set.
665 * @param dev device to set up
666 * @param bits number of bits used by gamma
667 * @param max value for gamma
668 * @param size of the gamma table
669 * @param gamma allocated gamma buffer to fill
670 */
sanei_genesys_generate_gamma_buffer(Genesys_Device * dev,const Genesys_Sensor & sensor,int bits,int max,int size,uint8_t * gamma)671 void sanei_genesys_generate_gamma_buffer(Genesys_Device* dev,
672 const Genesys_Sensor& sensor,
673 int bits,
674 int max,
675 int size,
676 uint8_t* gamma)
677 {
678 DBG_HELPER(dbg);
679 std::vector<uint16_t> rgamma = get_gamma_table(dev, sensor, GENESYS_RED);
680 std::vector<uint16_t> ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN);
681 std::vector<uint16_t> bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE);
682
683 if(dev->settings.contrast!=0 || dev->settings.brightness!=0)
684 {
685 std::vector<uint16_t> lut(65536);
686 sanei_genesys_load_lut(reinterpret_cast<unsigned char *>(lut.data()),
687 bits,
688 bits,
689 0,
690 max,
691 dev->settings.contrast,
692 dev->settings.brightness);
693 for (int i = 0; i < size; i++)
694 {
695 uint16_t value=rgamma[i];
696 value=lut[value];
697 gamma[i * 2 + size * 0 + 0] = value & 0xff;
698 gamma[i * 2 + size * 0 + 1] = (value >> 8) & 0xff;
699
700 value=ggamma[i];
701 value=lut[value];
702 gamma[i * 2 + size * 2 + 0] = value & 0xff;
703 gamma[i * 2 + size * 2 + 1] = (value >> 8) & 0xff;
704
705 value=bgamma[i];
706 value=lut[value];
707 gamma[i * 2 + size * 4 + 0] = value & 0xff;
708 gamma[i * 2 + size * 4 + 1] = (value >> 8) & 0xff;
709 }
710 }
711 else
712 {
713 for (int i = 0; i < size; i++)
714 {
715 uint16_t value=rgamma[i];
716 gamma[i * 2 + size * 0 + 0] = value & 0xff;
717 gamma[i * 2 + size * 0 + 1] = (value >> 8) & 0xff;
718
719 value=ggamma[i];
720 gamma[i * 2 + size * 2 + 0] = value & 0xff;
721 gamma[i * 2 + size * 2 + 1] = (value >> 8) & 0xff;
722
723 value=bgamma[i];
724 gamma[i * 2 + size * 4 + 0] = value & 0xff;
725 gamma[i * 2 + size * 4 + 1] = (value >> 8) & 0xff;
726 }
727 }
728 }
729
730
731 /** @brief send gamma table to scanner
732 * This function sends generic gamma table (ie ones built with
733 * provided gamma) or the user defined one if provided by
734 * fontend. Used by gl846+ ASICs
735 * @param dev device to write to
736 */
sanei_genesys_send_gamma_table(Genesys_Device * dev,const Genesys_Sensor & sensor)737 void sanei_genesys_send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor)
738 {
739 DBG_HELPER(dbg);
740 int size;
741 int i;
742
743 size = 256 + 1;
744
745 /* allocate temporary gamma tables: 16 bits words, 3 channels */
746 std::vector<uint8_t> gamma(size * 2 * 3, 255);
747
748 sanei_genesys_generate_gamma_buffer(dev, sensor, 16, 65535, size, gamma.data());
749
750 // loop sending gamma tables NOTE: 0x01000000 not 0x10000000
751 for (i = 0; i < 3; i++) {
752 // clear corresponding GMM_N bit
753 uint8_t val = dev->interface->read_register(0xbd);
754 val &= ~(0x01 << i);
755 dev->interface->write_register(0xbd, val);
756
757 // clear corresponding GMM_F bit
758 val = dev->interface->read_register(0xbe);
759 val &= ~(0x01 << i);
760 dev->interface->write_register(0xbe, val);
761
762 // FIXME: currently the last word of each gamma table is not initialized, so to work around
763 // unstable data, just set it to 0 which is the most likely value of uninitialized memory
764 // (proper value is probably 0xff)
765 gamma[size * 2 * i + size * 2 - 2] = 0;
766 gamma[size * 2 * i + size * 2 - 1] = 0;
767
768 /* set GMM_Z */
769 dev->interface->write_register(0xc5+2*i, gamma[size*2*i+1]);
770 dev->interface->write_register(0xc6+2*i, gamma[size*2*i]);
771
772 dev->interface->write_ahb(0x01000000 + 0x200 * i, (size-1) * 2,
773 gamma.data() + i * size * 2+2);
774 }
775 }
776
compute_session_pixel_offsets(const Genesys_Device * dev,ScanSession & s,const Genesys_Sensor & sensor)777 void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s,
778 const Genesys_Sensor& sensor)
779 {
780 if (dev->model->asic_type == AsicType::GL646) {
781 s.pixel_startx += s.output_startx * sensor.full_resolution / s.params.xres;
782 s.pixel_endx = s.pixel_startx + s.optical_pixels * s.full_resolution / s.optical_resolution;
783
784 } else if (dev->model->asic_type == AsicType::GL841 ||
785 dev->model->asic_type == AsicType::GL842 ||
786 dev->model->asic_type == AsicType::GL843 ||
787 dev->model->asic_type == AsicType::GL845 ||
788 dev->model->asic_type == AsicType::GL846 ||
789 dev->model->asic_type == AsicType::GL847)
790 {
791 unsigned startx_xres = s.optical_resolution;
792 if (dev->model->model_id == ModelId::CANON_5600F ||
793 dev->model->model_id == ModelId::CANON_LIDE_90)
794 {
795 if (s.output_resolution == 1200) {
796 startx_xres /= 2;
797 }
798 if (s.output_resolution >= 2400) {
799 startx_xres /= 4;
800 }
801 }
802 s.pixel_startx = (s.output_startx * startx_xres) / s.params.xres;
803 s.pixel_endx = s.pixel_startx + s.optical_pixels_raw;
804
805 } else if (dev->model->asic_type == AsicType::GL124)
806 {
807 s.pixel_startx = s.output_startx * sensor.full_resolution / s.params.xres;
808 s.pixel_endx = s.pixel_startx + s.optical_pixels_raw;
809 }
810
811 // align pixels to correct boundary for unstaggering
812 unsigned needed_x_alignment = std::max(s.stagger_x.size(), s.stagger_y.size());
813 unsigned aligned_pixel_startx = align_multiple_floor(s.pixel_startx, needed_x_alignment);
814 s.pixel_endx -= s.pixel_startx - aligned_pixel_startx;
815 s.pixel_startx = aligned_pixel_startx;
816
817 s.pixel_startx = sensor.pixel_count_ratio.apply(s.pixel_startx);
818 s.pixel_endx = sensor.pixel_count_ratio.apply(s.pixel_endx);
819
820 if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200 ||
821 dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
822 dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 ||
823 dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I)
824 {
825 s.pixel_startx = align_multiple_floor(s.pixel_startx, sensor.pixel_count_ratio.divisor());
826 s.pixel_endx = align_multiple_floor(s.pixel_endx, sensor.pixel_count_ratio.divisor());
827 }
828 }
829
session_adjust_output_pixels(unsigned output_pixels,const Genesys_Device & dev,const Genesys_Sensor & sensor,unsigned output_xresolution,unsigned output_yresolution,bool adjust_output_pixels)830 unsigned session_adjust_output_pixels(unsigned output_pixels,
831 const Genesys_Device& dev, const Genesys_Sensor& sensor,
832 unsigned output_xresolution, unsigned output_yresolution,
833 bool adjust_output_pixels)
834 {
835 bool adjust_optical_pixels = !adjust_output_pixels;
836 if (dev.model->model_id == ModelId::CANON_5600F) {
837 adjust_optical_pixels = true;
838 adjust_output_pixels = true;
839 }
840 if (adjust_optical_pixels) {
841 auto optical_resolution = sensor.get_optical_resolution();
842
843 // FIXME: better way would be to compute and return the required multiplier
844 unsigned optical_pixels = (output_pixels * optical_resolution) / output_xresolution;
845
846 if (dev.model->asic_type == AsicType::GL841 ||
847 dev.model->asic_type == AsicType::GL842)
848 {
849 optical_pixels = align_multiple_ceil(optical_pixels, 2);
850 }
851
852 if (dev.model->asic_type == AsicType::GL646 && output_xresolution == 400) {
853 optical_pixels = align_multiple_floor(optical_pixels, 6);
854 }
855
856 if (dev.model->asic_type == AsicType::GL843) {
857 // ensure the number of optical pixels is divisible by 2.
858 // In quarter-CCD mode optical_pixels is 4x larger than the actual physical number
859 optical_pixels = align_multiple_ceil(optical_pixels,
860 2 * sensor.full_resolution / optical_resolution);
861 if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200 ||
862 dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I ||
863 dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 ||
864 dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7400 ||
865 dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I ||
866 dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_8200I)
867 {
868 optical_pixels = align_multiple_ceil(optical_pixels, 16);
869 }
870 }
871 output_pixels = (optical_pixels * output_xresolution) / optical_resolution;
872 }
873
874 if (adjust_output_pixels) {
875 // TODO: the following may no longer be needed but were applied historically.
876
877 // we need an even pixels number
878 // TODO invert test logic or generalize behaviour across all ASICs
879 if (has_flag(dev.model->flags, ModelFlag::SIS_SENSOR) ||
880 dev.model->asic_type == AsicType::GL847 ||
881 dev.model->asic_type == AsicType::GL124 ||
882 dev.model->asic_type == AsicType::GL845 ||
883 dev.model->asic_type == AsicType::GL846 ||
884 dev.model->asic_type == AsicType::GL843)
885 {
886 if (output_xresolution <= 1200) {
887 output_pixels = align_multiple_floor(output_pixels, 4);
888 } else if (output_xresolution < output_yresolution) {
889 // BUG: this is an artifact of the fact that the resolution was twice as large than
890 // the actual resolution when scanning above the supported scanner X resolution
891 output_pixels = align_multiple_floor(output_pixels, 8);
892 } else {
893 output_pixels = align_multiple_floor(output_pixels, 16);
894 }
895 }
896
897 // corner case for true lineart for sensor with several segments or when xres is doubled
898 // to match yres */
899 if (output_xresolution >= 1200 && (
900 dev.model->asic_type == AsicType::GL124 ||
901 dev.model->asic_type == AsicType::GL847 ||
902 dev.session.params.xres < dev.session.params.yres))
903 {
904 if (output_xresolution < output_yresolution) {
905 // FIXME: this is an artifact of the fact that the resolution was twice as large than
906 // the actual resolution when scanning above the supported scanner X resolution
907 output_pixels = align_multiple_floor(output_pixels, 8);
908 } else {
909 output_pixels = align_multiple_floor(output_pixels, 16);
910 }
911 }
912 }
913
914 return output_pixels;
915 }
916
compute_session(const Genesys_Device * dev,ScanSession & s,const Genesys_Sensor & sensor)917 void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor)
918 {
919 DBG_HELPER(dbg);
920
921 (void) dev;
922 s.params.assert_valid();
923
924 if (s.params.depth != 8 && s.params.depth != 16) {
925 throw SaneException("Unsupported depth setting %d", s.params.depth);
926 }
927
928 // compute optical and output resolutions
929 s.full_resolution = sensor.full_resolution;
930 s.optical_resolution = sensor.get_optical_resolution();
931 s.output_resolution = s.params.xres;
932
933 s.pixel_count_ratio = sensor.pixel_count_ratio;
934
935 if (s.output_resolution > s.optical_resolution) {
936 throw std::runtime_error("output resolution higher than optical resolution");
937 }
938
939 s.output_pixels = session_adjust_output_pixels(s.params.pixels, *dev, sensor,
940 s.params.xres, s.params.yres, false);
941
942 // Compute the number of optical pixels that will be acquired by the chip.
943 // The necessary alignment requirements have already been computed by
944 // get_session_output_pixels_multiplier
945 s.optical_pixels = (s.output_pixels * s.optical_resolution) / s.output_resolution;
946
947 if (static_cast<int>(s.params.startx) + sensor.output_pixel_offset < 0)
948 throw SaneException("Invalid sensor.output_pixel_offset");
949 s.output_startx = static_cast<unsigned>(
950 static_cast<int>(s.params.startx) + sensor.output_pixel_offset);
951
952 s.stagger_x = sensor.stagger_x;
953 s.stagger_y = sensor.stagger_y;
954
955 s.num_staggered_lines = 0;
956 if (!has_flag(s.params.flags, ScanFlag::IGNORE_STAGGER_OFFSET)) {
957 s.num_staggered_lines = s.stagger_y.max_shift() * s.params.yres / s.params.xres;
958 }
959
960 s.color_shift_lines_r = dev->model->ld_shift_r;
961 s.color_shift_lines_g = dev->model->ld_shift_g;
962 s.color_shift_lines_b = dev->model->ld_shift_b;
963
964 if (dev->model->motor_id == MotorId::G4050 && s.params.yres > 600) {
965 // it seems base_dpi of the G4050 motor is changed above 600 dpi
966 s.color_shift_lines_r = (s.color_shift_lines_r * 3800) / dev->motor.base_ydpi;
967 s.color_shift_lines_g = (s.color_shift_lines_g * 3800) / dev->motor.base_ydpi;
968 s.color_shift_lines_b = (s.color_shift_lines_b * 3800) / dev->motor.base_ydpi;
969 }
970
971 s.color_shift_lines_r = (s.color_shift_lines_r * s.params.yres) / dev->motor.base_ydpi;
972 s.color_shift_lines_g = (s.color_shift_lines_g * s.params.yres) / dev->motor.base_ydpi;
973 s.color_shift_lines_b = (s.color_shift_lines_b * s.params.yres) / dev->motor.base_ydpi;
974
975 s.max_color_shift_lines = 0;
976 if (s.params.channels > 1 && !has_flag(s.params.flags, ScanFlag::IGNORE_COLOR_OFFSET)) {
977 s.max_color_shift_lines = std::max(s.color_shift_lines_r, std::max(s.color_shift_lines_g,
978 s.color_shift_lines_b));
979 }
980
981 s.output_line_count = s.params.lines + s.max_color_shift_lines + s.num_staggered_lines;
982 s.optical_line_count = dev->model->is_cis ? s.output_line_count * s.params.channels
983 : s.output_line_count;
984
985 s.output_channel_bytes = multiply_by_depth_ceil(s.output_pixels, s.params.depth);
986 s.output_line_bytes = s.output_channel_bytes * s.params.channels;
987
988 s.segment_count = sensor.get_segment_count();
989
990 s.optical_pixels_raw = s.optical_pixels;
991 s.output_line_bytes_raw = s.output_line_bytes;
992 s.conseq_pixel_dist = 0;
993
994 // FIXME: Use ModelFlag::SIS_SENSOR
995 if ((dev->model->asic_type == AsicType::GL845 ||
996 dev->model->asic_type == AsicType::GL846 ||
997 dev->model->asic_type == AsicType::GL847) &&
998 dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7400 &&
999 dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_8200I)
1000 {
1001 if (s.segment_count > 1) {
1002 s.conseq_pixel_dist = sensor.segment_size;
1003
1004 // in case of multi-segments sensor, we have expand the scan area to sensor boundary
1005 if (dev->model->model_id == ModelId::CANON_5600F) {
1006 unsigned startx_xres = s.optical_resolution;
1007 if (dev->model->model_id == ModelId::CANON_5600F) {
1008 if (s.output_resolution == 1200) {
1009 startx_xres /= 2;
1010 }
1011 if (s.output_resolution >= 2400) {
1012 startx_xres /= 4;
1013 }
1014 }
1015 unsigned optical_startx = s.output_startx * startx_xres / s.params.xres;
1016 unsigned optical_endx = optical_startx + s.optical_pixels;
1017
1018 unsigned multi_segment_size_output = s.segment_count * s.conseq_pixel_dist;
1019 unsigned multi_segment_size_optical =
1020 (multi_segment_size_output * s.optical_resolution) / s.output_resolution;
1021
1022 optical_endx = align_multiple_ceil(optical_endx, multi_segment_size_optical);
1023 s.optical_pixels_raw = optical_endx - optical_startx;
1024 s.optical_pixels_raw = align_multiple_floor(s.optical_pixels_raw,
1025 4 * s.optical_resolution / s.output_resolution);
1026 } else {
1027 // BUG: the following code will likely scan too much. Use the CANON_5600F approach
1028 unsigned extra_segment_scan_area = align_multiple_ceil(s.conseq_pixel_dist, 2);
1029 extra_segment_scan_area *= s.segment_count - 1;
1030 extra_segment_scan_area = s.pixel_count_ratio.apply_inverse(extra_segment_scan_area);
1031
1032 s.optical_pixels_raw += extra_segment_scan_area;
1033 }
1034 }
1035
1036 if (dev->model->model_id == ModelId::CANON_5600F) {
1037 auto output_pixels_raw = (s.optical_pixels_raw * s.output_resolution) / s.optical_resolution;
1038 auto output_channel_bytes_raw = multiply_by_depth_ceil(output_pixels_raw, s.params.depth);
1039 s.output_line_bytes_raw = output_channel_bytes_raw * s.params.channels;
1040 } else {
1041 s.output_line_bytes_raw = multiply_by_depth_ceil(
1042 (s.optical_pixels_raw * s.output_resolution) / sensor.full_resolution / s.segment_count,
1043 s.params.depth);
1044 }
1045 }
1046
1047 if (dev->model->asic_type == AsicType::GL841 ||
1048 dev->model->asic_type == AsicType::GL842)
1049 {
1050 if (dev->model->is_cis) {
1051 s.output_line_bytes_raw = s.output_channel_bytes;
1052 }
1053 }
1054
1055 if (dev->model->asic_type == AsicType::GL124) {
1056 if (dev->model->is_cis) {
1057 s.output_line_bytes_raw = s.output_channel_bytes;
1058 }
1059 s.conseq_pixel_dist = s.output_pixels / (s.full_resolution / s.optical_resolution) / s.segment_count;
1060 }
1061
1062 if (dev->model->asic_type == AsicType::GL842 ||
1063 dev->model->asic_type == AsicType::GL843)
1064 {
1065 if (dev->model->is_cis) {
1066 if (s.segment_count > 1) {
1067 s.conseq_pixel_dist = sensor.segment_size;
1068 }
1069 } else {
1070 s.conseq_pixel_dist = s.output_pixels / s.segment_count;
1071 }
1072 }
1073
1074 s.output_segment_pixel_group_count = 0;
1075 if (dev->model->asic_type == AsicType::GL124 ||
1076 dev->model->asic_type == AsicType::GL842 ||
1077 dev->model->asic_type == AsicType::GL843)
1078 {
1079 s.output_segment_pixel_group_count = s.output_pixels /
1080 (s.full_resolution / s.optical_resolution * s.segment_count);
1081 }
1082
1083 if (dev->model->model_id == ModelId::CANON_LIDE_90) {
1084 s.output_segment_pixel_group_count = s.output_pixels / s.segment_count;
1085 }
1086
1087 if (dev->model->asic_type == AsicType::GL845 ||
1088 dev->model->asic_type == AsicType::GL846 ||
1089 dev->model->asic_type == AsicType::GL847)
1090 {
1091 if (dev->model->model_id == ModelId::CANON_5600F) {
1092 s.output_segment_pixel_group_count = s.output_pixels / s.segment_count;
1093 } else {
1094 s.output_segment_pixel_group_count = s.pixel_count_ratio.apply(s.optical_pixels);
1095 }
1096 }
1097
1098 s.output_line_bytes_requested = multiply_by_depth_ceil(
1099 s.params.get_requested_pixels() * s.params.channels, s.params.depth);
1100
1101 s.output_total_bytes_raw = s.output_line_bytes_raw * s.output_line_count;
1102 s.output_total_bytes = s.output_line_bytes * s.output_line_count;
1103 if (dev->model->model_id == ModelId::CANON_LIDE_90) {
1104 s.output_total_bytes_raw *= s.params.channels;
1105 s.output_total_bytes *= s.params.channels;
1106 }
1107
1108 s.buffer_size_read = s.output_line_bytes_raw * 64;
1109 compute_session_pixel_offsets(dev, s, sensor);
1110
1111 s.shading_pixel_offset = sensor.shading_pixel_offset;
1112
1113 if (dev->model->asic_type == AsicType::GL124 ||
1114 dev->model->asic_type == AsicType::GL845 ||
1115 dev->model->asic_type == AsicType::GL846)
1116 {
1117 s.enable_ledadd = (s.params.channels == 1 && dev->model->is_cis && dev->settings.true_gray);
1118 }
1119
1120 s.use_host_side_calib = sensor.use_host_side_calib;
1121
1122 if (dev->model->asic_type == AsicType::GL841 ||
1123 dev->model->asic_type == AsicType::GL842 ||
1124 dev->model->asic_type == AsicType::GL843)
1125 {
1126 // no 16 bit gamma for this ASIC
1127 if (s.params.depth == 16) {
1128 s.params.flags |= ScanFlag::DISABLE_GAMMA;
1129 }
1130 }
1131
1132 s.computed = true;
1133
1134 DBG(DBG_info, "%s ", __func__);
1135 debug_dump(DBG_info, s);
1136 }
1137
build_image_pipeline(const Genesys_Device & dev,const ScanSession & session,unsigned pipeline_index,bool log_image_data)1138 ImagePipelineStack build_image_pipeline(const Genesys_Device& dev, const ScanSession& session,
1139 unsigned pipeline_index, bool log_image_data)
1140 {
1141 auto format = create_pixel_format(session.params.depth,
1142 dev.model->is_cis ? 1 : session.params.channels,
1143 dev.model->line_mode_color_order);
1144 auto depth = get_pixel_format_depth(format);
1145 auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw);
1146
1147 auto read_data_from_usb = [&dev](std::size_t size, std::uint8_t* data)
1148 {
1149 DBG(DBG_info, "read_data_from_usb: reading %zu bytes\n", size);
1150 auto begin = std::chrono::high_resolution_clock::now();
1151 dev.interface->bulk_read_data(0x45, data, size);
1152 auto end = std::chrono::high_resolution_clock::now();
1153 float us = std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count();
1154 float speed = size / us; // bytes/us == MB/s
1155 DBG(DBG_info, "read_data_from_usb: reading %zu bytes finished %f MB/s\n", size, speed);
1156 return true;
1157 };
1158
1159 auto debug_prefix = "gl_pipeline_" + std::to_string(pipeline_index);
1160
1161 ImagePipelineStack pipeline;
1162
1163 auto lines = session.optical_line_count;
1164 auto buffer_size = session.buffer_size_read;
1165
1166 // At least GL841 requires reads to be aligned to 2 bytes and will fail on some devices on
1167 // certain circumstances.
1168 buffer_size = align_multiple_ceil(buffer_size, 2);
1169
1170 auto& src_node = pipeline.push_first_node<ImagePipelineNodeBufferedCallableSource>(
1171 width, lines, format, buffer_size, read_data_from_usb);
1172 src_node.set_last_read_multiple(2);
1173
1174 if (log_image_data) {
1175 pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_0_from_usb.tiff");
1176 }
1177
1178 if (session.segment_count > 1) {
1179 auto output_width = session.output_segment_pixel_group_count * session.segment_count;
1180 pipeline.push_node<ImagePipelineNodeDesegment>(output_width, dev.segment_order,
1181 session.conseq_pixel_dist,
1182 1, 1);
1183
1184 if (log_image_data) {
1185 pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_1_after_desegment.tiff");
1186 }
1187 }
1188
1189 if (depth == 16) {
1190 unsigned num_swaps = 0;
1191 if (has_flag(dev.model->flags, ModelFlag::SWAP_16BIT_DATA)) {
1192 num_swaps++;
1193 }
1194 #ifdef WORDS_BIGENDIAN
1195 num_swaps++;
1196 #endif
1197 if (num_swaps % 2 != 0) {
1198 pipeline.push_node<ImagePipelineNodeSwap16BitEndian>();
1199
1200 if (log_image_data) {
1201 pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_2_after_swap.tiff");
1202 }
1203 }
1204 }
1205
1206 if (has_flag(dev.model->flags, ModelFlag::INVERT_PIXEL_DATA)) {
1207 pipeline.push_node<ImagePipelineNodeInvert>();
1208
1209 if (log_image_data) {
1210 pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_3_after_invert.tiff");
1211 }
1212 }
1213
1214 if (dev.model->is_cis && session.params.channels == 3) {
1215 pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev.model->line_mode_color_order);
1216
1217 if (log_image_data) {
1218 pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_4_after_merge_mono.tiff");
1219 }
1220 }
1221
1222 if (pipeline.get_output_format() == PixelFormat::BGR888) {
1223 pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB888);
1224 }
1225
1226 if (pipeline.get_output_format() == PixelFormat::BGR161616) {
1227 pipeline.push_node<ImagePipelineNodeFormatConvert>(PixelFormat::RGB161616);
1228 }
1229
1230 if (log_image_data) {
1231 pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_5_after_format.tiff");
1232 }
1233
1234 if (session.max_color_shift_lines > 0 && session.params.channels == 3) {
1235 pipeline.push_node<ImagePipelineNodeComponentShiftLines>(
1236 session.color_shift_lines_r,
1237 session.color_shift_lines_g,
1238 session.color_shift_lines_b);
1239
1240 if (log_image_data) {
1241 pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_6_after_color_unshift.tiff");
1242 }
1243 }
1244
1245 if (!session.stagger_x.empty()) {
1246 // FIXME: the image will be scaled to requested pixel count without regard to the reduction
1247 // of image size in this step.
1248 pipeline.push_node<ImagePipelineNodePixelShiftColumns>(session.stagger_x.shifts());
1249
1250 if (log_image_data) {
1251 pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_7_after_x_unstagger.tiff");
1252 }
1253 }
1254
1255 if (session.num_staggered_lines > 0) {
1256 pipeline.push_node<ImagePipelineNodePixelShiftLines>(session.stagger_y.shifts());
1257
1258 if (log_image_data) {
1259 pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_8_after_y_unstagger.tiff");
1260 }
1261 }
1262
1263 if (session.use_host_side_calib &&
1264 !has_flag(dev.model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) &&
1265 !has_flag(session.params.flags, ScanFlag::DISABLE_SHADING))
1266 {
1267 unsigned offset_pixels = session.params.startx + dev.calib_session.shading_pixel_offset;
1268 unsigned offset_bytes = offset_pixels * dev.calib_session.params.channels;
1269 pipeline.push_node<ImagePipelineNodeCalibrate>(dev.dark_average_data,
1270 dev.white_average_data, offset_bytes);
1271
1272 if (log_image_data) {
1273 pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_9_after_calibrate.tiff");
1274 }
1275 }
1276
1277 if (pipeline.get_output_width() != session.params.get_requested_pixels()) {
1278 pipeline.push_node<ImagePipelineNodeScaleRows>(session.params.get_requested_pixels());
1279 }
1280
1281 return pipeline;
1282 }
1283
setup_image_pipeline(Genesys_Device & dev,const ScanSession & session)1284 void setup_image_pipeline(Genesys_Device& dev, const ScanSession& session)
1285 {
1286 static unsigned s_pipeline_index = 0;
1287
1288 s_pipeline_index++;
1289
1290 dev.pipeline = build_image_pipeline(dev, session, s_pipeline_index, dbg_log_image_data());
1291
1292 auto read_from_pipeline = [&dev](std::size_t size, std::uint8_t* out_data)
1293 {
1294 (void) size; // will be always equal to dev.pipeline.get_output_row_bytes()
1295 return dev.pipeline.get_next_row_data(out_data);
1296 };
1297 dev.pipeline_buffer = ImageBuffer{dev.pipeline.get_output_row_bytes(),
1298 read_from_pipeline};
1299 }
1300
compute_frontend_gain_wolfson(float value,float target_value)1301 std::uint8_t compute_frontend_gain_wolfson(float value, float target_value)
1302 {
1303 /* the flow of data through the frontend ADC is as follows (see e.g. WM8192 datasheet)
1304 input
1305 -> apply offset (o = i + 260mV * (DAC[7:0]-127.5)/127.5) ->
1306 -> apply gain (o = i * 208/(283-PGA[7:0])
1307 -> ADC
1308
1309 Here we have some input data that was acquired with zero gain (PGA==0).
1310 We want to compute gain such that the output would approach full ADC range (controlled by
1311 target_value).
1312
1313 We want to solve the following for {PGA}:
1314
1315 {value} = {input} * 208 / (283 - 0)
1316 {target_value} = {input} * 208 / (283 - {PGA})
1317
1318 The solution is the following equation:
1319
1320 {PGA} = 283 * (1 - {value} / {target_value})
1321 */
1322 float gain = value / target_value;
1323 int code = static_cast<int>(283 * (1 - gain));
1324 return clamp(code, 0, 255);
1325 }
1326
compute_frontend_gain_lide_80(float value,float target_value)1327 std::uint8_t compute_frontend_gain_lide_80(float value, float target_value)
1328 {
1329 int code = static_cast<int>((target_value / value) * 12);
1330 return clamp(code, 0, 255);
1331 }
1332
compute_frontend_gain_wolfson_gl841(float value,float target_value)1333 std::uint8_t compute_frontend_gain_wolfson_gl841(float value, float target_value)
1334 {
1335 // this code path is similar to what generic wolfson code path uses and uses similar constants,
1336 // but is likely incorrect.
1337 float inv_gain = target_value / value;
1338 inv_gain *= 0.69f;
1339 int code = static_cast<int>(283 - 208 / inv_gain);
1340 return clamp(code, 0, 255);
1341 }
1342
compute_frontend_gain_wolfson_gl846_gl847_gl124(float value,float target_value)1343 std::uint8_t compute_frontend_gain_wolfson_gl846_gl847_gl124(float value, float target_value)
1344 {
1345 // this code path is similar to what generic wolfson code path uses and uses similar constants,
1346 // but is likely incorrect.
1347 float inv_gain = target_value / value;
1348 int code = static_cast<int>(283 - 208 / inv_gain);
1349 return clamp(code, 0, 255);
1350 }
1351
1352
compute_frontend_gain_analog_devices(float value,float target_value)1353 std::uint8_t compute_frontend_gain_analog_devices(float value, float target_value)
1354 {
1355 /* The flow of data through the frontend ADC is as follows (see e.g. AD9826 datasheet)
1356 input
1357 -> apply offset (o = i + 300mV * (OFFSET[8] ? 1 : -1) * (OFFSET[7:0] / 127)
1358 -> apply gain (o = i * 6 / (1 + 5 * ( 63 - PGA[5:0] ) / 63 ) )
1359 -> ADC
1360
1361 We want to solve the following for {PGA}:
1362
1363 {value} = {input} * 6 / (1 + 5 * ( 63 - 0) / 63 ) )
1364 {target_value} = {input} * 6 / (1 + 5 * ( 63 - {PGA}) / 63 ) )
1365
1366 The solution is the following equation:
1367
1368 {PGA} = (378 / 5) * ({target_value} - {value} / {target_value})
1369 */
1370 int code = static_cast<int>((378.0f / 5.0f) * ((target_value - value) / target_value));
1371 return clamp(code, 0, 63);
1372 }
1373
compute_frontend_gain(float value,float target_value,FrontendType frontend_type)1374 std::uint8_t compute_frontend_gain(float value, float target_value,
1375 FrontendType frontend_type)
1376 {
1377 switch (frontend_type) {
1378 case FrontendType::WOLFSON:
1379 return compute_frontend_gain_wolfson(value, target_value);
1380 case FrontendType::ANALOG_DEVICES:
1381 return compute_frontend_gain_analog_devices(value, target_value);
1382 case FrontendType::CANON_LIDE_80:
1383 return compute_frontend_gain_lide_80(value, target_value);
1384 case FrontendType::WOLFSON_GL841:
1385 return compute_frontend_gain_wolfson_gl841(value, target_value);
1386 case FrontendType::WOLFSON_GL846:
1387 case FrontendType::ANALOG_DEVICES_GL847:
1388 case FrontendType::WOLFSON_GL124:
1389 return compute_frontend_gain_wolfson_gl846_gl847_gl124(value, target_value);
1390 default:
1391 throw SaneException("Unknown frontend to compute gain for");
1392 }
1393 }
1394
1395 /** @brief initialize device
1396 * Initialize backend and ASIC : registers, motor tables, and gamma tables
1397 * then ensure scanner's head is at home. Designed for gl846+ ASICs.
1398 * Detects cold boot (ie first boot since device plugged) in this case
1399 * an extensice setup up is done at hardware level.
1400 *
1401 * @param dev device to initialize
1402 * @param max_regs umber of maximum used registers
1403 */
sanei_genesys_asic_init(Genesys_Device * dev)1404 void sanei_genesys_asic_init(Genesys_Device* dev)
1405 {
1406 DBG_HELPER(dbg);
1407
1408 uint8_t val;
1409 bool cold = true;
1410
1411 // URB 16 control 0xc0 0x0c 0x8e 0x0b len 1 read 0x00 */
1412 dev->interface->get_usb_device().control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER,
1413 VALUE_GET_REGISTER, 0x00, 1, &val);
1414
1415 DBG (DBG_io2, "%s: value=0x%02x\n", __func__, val);
1416 DBG (DBG_info, "%s: device is %s\n", __func__, (val & 0x08) ? "USB 1.0" : "USB2.0");
1417 if (val & 0x08)
1418 {
1419 dev->usb_mode = 1;
1420 }
1421 else
1422 {
1423 dev->usb_mode = 2;
1424 }
1425
1426 /* Check if the device has already been initialized and powered up. We read register 0x06 and
1427 check PWRBIT, if reset scanner has been freshly powered up. This bit will be set to later
1428 so that following reads can detect power down/up cycle
1429 */
1430 if (!is_testing_mode()) {
1431 if (dev->interface->read_register(0x06) & 0x10) {
1432 cold = false;
1433 }
1434 }
1435 DBG (DBG_info, "%s: device is %s\n", __func__, cold ? "cold" : "warm");
1436
1437 /* don't do anything if backend is initialized and hardware hasn't been
1438 * replug */
1439 if (dev->already_initialized && !cold)
1440 {
1441 DBG (DBG_info, "%s: already initialized, nothing to do\n", __func__);
1442 return;
1443 }
1444
1445 // set up hardware and registers
1446 dev->cmd_set->asic_boot(dev, cold);
1447
1448 /* now hardware part is OK, set up device struct */
1449 dev->white_average_data.clear();
1450 dev->dark_average_data.clear();
1451
1452 dev->settings.color_filter = ColorFilter::RED;
1453
1454 dev->initial_regs = dev->reg;
1455
1456 const auto& sensor = sanei_genesys_find_sensor_any(dev);
1457
1458 // Set analog frontend
1459 dev->cmd_set->set_fe(dev, sensor, AFE_INIT);
1460
1461 dev->already_initialized = true;
1462
1463 // Move to home if needed
1464 if (dev->model->model_id == ModelId::CANON_8600F) {
1465 if (!dev->cmd_set->is_head_home(*dev, ScanHeadId::SECONDARY)) {
1466 dev->set_head_pos_unknown(ScanHeadId::SECONDARY);
1467 }
1468 if (!dev->cmd_set->is_head_home(*dev, ScanHeadId::PRIMARY)) {
1469 dev->set_head_pos_unknown(ScanHeadId::SECONDARY);
1470 }
1471 }
1472 dev->cmd_set->move_back_home(dev, true);
1473
1474 // Set powersaving (default = 15 minutes)
1475 dev->cmd_set->set_powersaving(dev, 15);
1476 }
1477
scanner_start_action(Genesys_Device & dev,bool start_motor)1478 void scanner_start_action(Genesys_Device& dev, bool start_motor)
1479 {
1480 DBG_HELPER(dbg);
1481 switch (dev.model->asic_type) {
1482 case AsicType::GL646:
1483 case AsicType::GL841:
1484 case AsicType::GL842:
1485 case AsicType::GL843:
1486 case AsicType::GL845:
1487 case AsicType::GL846:
1488 case AsicType::GL847:
1489 case AsicType::GL124:
1490 break;
1491 default:
1492 throw SaneException("Unsupported chip");
1493 }
1494
1495 if (start_motor) {
1496 dev.interface->write_register(0x0f, 0x01);
1497 } else {
1498 dev.interface->write_register(0x0f, 0);
1499 }
1500 }
1501
sanei_genesys_set_dpihw(Genesys_Register_Set & regs,unsigned dpihw)1502 void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, unsigned dpihw)
1503 {
1504 // same across GL646, GL841, GL843, GL846, GL847, GL124
1505 const uint8_t REG_0x05_DPIHW_MASK = 0xc0;
1506 const uint8_t REG_0x05_DPIHW_600 = 0x00;
1507 const uint8_t REG_0x05_DPIHW_1200 = 0x40;
1508 const uint8_t REG_0x05_DPIHW_2400 = 0x80;
1509 const uint8_t REG_0x05_DPIHW_4800 = 0xc0;
1510
1511 uint8_t dpihw_setting;
1512 switch (dpihw) {
1513 case 600:
1514 dpihw_setting = REG_0x05_DPIHW_600;
1515 break;
1516 case 1200:
1517 dpihw_setting = REG_0x05_DPIHW_1200;
1518 break;
1519 case 2400:
1520 dpihw_setting = REG_0x05_DPIHW_2400;
1521 break;
1522 case 4800:
1523 dpihw_setting = REG_0x05_DPIHW_4800;
1524 break;
1525 default:
1526 throw SaneException("Unknown dpihw value: %d", dpihw);
1527 }
1528 regs.set8_mask(0x05, dpihw_setting, REG_0x05_DPIHW_MASK);
1529 }
1530
regs_set_exposure(AsicType asic_type,Genesys_Register_Set & regs,const SensorExposure & exposure)1531 void regs_set_exposure(AsicType asic_type, Genesys_Register_Set& regs,
1532 const SensorExposure& exposure)
1533 {
1534 switch (asic_type) {
1535 case AsicType::GL124: {
1536 regs.set24(gl124::REG_EXPR, exposure.red);
1537 regs.set24(gl124::REG_EXPG, exposure.green);
1538 regs.set24(gl124::REG_EXPB, exposure.blue);
1539 break;
1540 }
1541 case AsicType::GL646: {
1542 regs.set16(gl646::REG_EXPR, exposure.red);
1543 regs.set16(gl646::REG_EXPG, exposure.green);
1544 regs.set16(gl646::REG_EXPB, exposure.blue);
1545 break;
1546 }
1547 case AsicType::GL841: {
1548 regs.set16(gl841::REG_EXPR, exposure.red);
1549 regs.set16(gl841::REG_EXPG, exposure.green);
1550 regs.set16(gl841::REG_EXPB, exposure.blue);
1551 break;
1552 }
1553 case AsicType::GL842: {
1554 regs.set16(gl842::REG_EXPR, exposure.red);
1555 regs.set16(gl842::REG_EXPG, exposure.green);
1556 regs.set16(gl842::REG_EXPB, exposure.blue);
1557 break;
1558 }
1559 case AsicType::GL843: {
1560 regs.set16(gl843::REG_EXPR, exposure.red);
1561 regs.set16(gl843::REG_EXPG, exposure.green);
1562 regs.set16(gl843::REG_EXPB, exposure.blue);
1563 break;
1564 }
1565 case AsicType::GL845:
1566 case AsicType::GL846: {
1567 regs.set16(gl846::REG_EXPR, exposure.red);
1568 regs.set16(gl846::REG_EXPG, exposure.green);
1569 regs.set16(gl846::REG_EXPB, exposure.blue);
1570 break;
1571 }
1572 case AsicType::GL847: {
1573 regs.set16(gl847::REG_EXPR, exposure.red);
1574 regs.set16(gl847::REG_EXPG, exposure.green);
1575 regs.set16(gl847::REG_EXPB, exposure.blue);
1576 break;
1577 }
1578 default:
1579 throw SaneException("Unsupported asic");
1580 }
1581 }
1582
regs_set_optical_off(AsicType asic_type,Genesys_Register_Set & regs)1583 void regs_set_optical_off(AsicType asic_type, Genesys_Register_Set& regs)
1584 {
1585 DBG_HELPER(dbg);
1586 switch (asic_type) {
1587 case AsicType::GL646: {
1588 regs.find_reg(gl646::REG_0x01).value &= ~gl646::REG_0x01_SCAN;
1589 break;
1590 }
1591 case AsicType::GL841: {
1592 regs.find_reg(gl841::REG_0x01).value &= ~gl841::REG_0x01_SCAN;
1593 break;
1594 }
1595 case AsicType::GL842: {
1596 regs.find_reg(gl842::REG_0x01).value &= ~gl842::REG_0x01_SCAN;
1597 break;
1598 }
1599 case AsicType::GL843: {
1600 regs.find_reg(gl843::REG_0x01).value &= ~gl843::REG_0x01_SCAN;
1601 break;
1602 }
1603 case AsicType::GL845:
1604 case AsicType::GL846: {
1605 regs.find_reg(gl846::REG_0x01).value &= ~gl846::REG_0x01_SCAN;
1606 break;
1607 }
1608 case AsicType::GL847: {
1609 regs.find_reg(gl847::REG_0x01).value &= ~gl847::REG_0x01_SCAN;
1610 break;
1611 }
1612 case AsicType::GL124: {
1613 regs.find_reg(gl124::REG_0x01).value &= ~gl124::REG_0x01_SCAN;
1614 break;
1615 }
1616 default:
1617 throw SaneException("Unsupported asic");
1618 }
1619 }
1620
get_registers_gain4_bit(AsicType asic_type,const Genesys_Register_Set & regs)1621 bool get_registers_gain4_bit(AsicType asic_type, const Genesys_Register_Set& regs)
1622 {
1623 switch (asic_type) {
1624 case AsicType::GL646:
1625 return static_cast<bool>(regs.get8(gl646::REG_0x06) & gl646::REG_0x06_GAIN4);
1626 case AsicType::GL841:
1627 return static_cast<bool>(regs.get8(gl841::REG_0x06) & gl841::REG_0x06_GAIN4);
1628 case AsicType::GL842:
1629 return static_cast<bool>(regs.get8(gl842::REG_0x06) & gl842::REG_0x06_GAIN4);
1630 case AsicType::GL843:
1631 return static_cast<bool>(regs.get8(gl843::REG_0x06) & gl843::REG_0x06_GAIN4);
1632 case AsicType::GL845:
1633 case AsicType::GL846:
1634 return static_cast<bool>(regs.get8(gl846::REG_0x06) & gl846::REG_0x06_GAIN4);
1635 case AsicType::GL847:
1636 return static_cast<bool>(regs.get8(gl847::REG_0x06) & gl847::REG_0x06_GAIN4);
1637 case AsicType::GL124:
1638 return static_cast<bool>(regs.get8(gl124::REG_0x06) & gl124::REG_0x06_GAIN4);
1639 default:
1640 throw SaneException("Unsupported chipset");
1641 }
1642 }
1643
1644 /**
1645 * Wait for the scanning head to park
1646 */
sanei_genesys_wait_for_home(Genesys_Device * dev)1647 void sanei_genesys_wait_for_home(Genesys_Device* dev)
1648 {
1649 DBG_HELPER(dbg);
1650
1651 /* clear the parking status whatever the outcome of the function */
1652 dev->parking = false;
1653
1654 if (is_testing_mode()) {
1655 return;
1656 }
1657
1658 // read initial status, if head isn't at home and motor is on we are parking, so we wait.
1659 // gl847/gl124 need 2 reads for reliable results
1660 auto status = scanner_read_status(*dev);
1661 dev->interface->sleep_ms(10);
1662 status = scanner_read_status(*dev);
1663
1664 if (status.is_at_home) {
1665 DBG (DBG_info,
1666 "%s: already at home\n", __func__);
1667 return;
1668 }
1669
1670 unsigned timeout_ms = 200000;
1671 unsigned elapsed_ms = 0;
1672 do
1673 {
1674 dev->interface->sleep_ms(100);
1675 elapsed_ms += 100;
1676
1677 status = scanner_read_status(*dev);
1678 } while (elapsed_ms < timeout_ms && !status.is_at_home);
1679
1680 /* if after the timeout, head is still not parked, error out */
1681 if (elapsed_ms >= timeout_ms && !status.is_at_home) {
1682 DBG (DBG_error, "%s: failed to reach park position in %dseconds\n", __func__,
1683 timeout_ms / 1000);
1684 throw SaneException(SANE_STATUS_IO_ERROR, "failed to reach park position");
1685 }
1686 }
1687
get_motor_profile_ptr(const std::vector<MotorProfile> & profiles,unsigned exposure,const ScanSession & session)1688 const MotorProfile* get_motor_profile_ptr(const std::vector<MotorProfile>& profiles,
1689 unsigned exposure,
1690 const ScanSession& session)
1691 {
1692 int best_i = -1;
1693
1694 for (unsigned i = 0; i < profiles.size(); ++i) {
1695 const auto& profile = profiles[i];
1696
1697 if (!profile.resolutions.matches(session.params.yres)) {
1698 continue;
1699 }
1700 if (!profile.scan_methods.matches(session.params.scan_method)) {
1701 continue;
1702 }
1703
1704 if (profile.max_exposure == exposure) {
1705 return &profile;
1706 }
1707
1708 if (profile.max_exposure == 0 || profile.max_exposure >= exposure) {
1709 if (best_i < 0) {
1710 // no match found yet
1711 best_i = i;
1712 } else {
1713 // test for better match
1714 if (profiles[i].max_exposure < profiles[best_i].max_exposure) {
1715 best_i = i;
1716 }
1717 }
1718 }
1719 }
1720
1721 if (best_i < 0) {
1722 return nullptr;
1723 }
1724
1725 return &profiles[best_i];
1726 }
1727
get_motor_profile(const std::vector<MotorProfile> & profiles,unsigned exposure,const ScanSession & session)1728 const MotorProfile& get_motor_profile(const std::vector<MotorProfile>& profiles,
1729 unsigned exposure,
1730 const ScanSession& session)
1731 {
1732 const auto* profile = get_motor_profile_ptr(profiles, exposure, session);
1733 if (profile == nullptr) {
1734 throw SaneException("Motor slope is not configured");
1735 }
1736
1737 return *profile;
1738 }
1739
create_slope_table(AsicType asic_type,const Genesys_Motor & motor,unsigned ydpi,unsigned exposure,unsigned step_multiplier,const MotorProfile & motor_profile)1740 MotorSlopeTable create_slope_table(AsicType asic_type, const Genesys_Motor& motor, unsigned ydpi,
1741 unsigned exposure, unsigned step_multiplier,
1742 const MotorProfile& motor_profile)
1743 {
1744 unsigned target_speed_w = ((exposure * ydpi) / motor.base_ydpi);
1745
1746 auto table = create_slope_table_for_speed(motor_profile.slope, target_speed_w,
1747 motor_profile.step_type,
1748 step_multiplier, 2 * step_multiplier,
1749 get_slope_table_max_size(asic_type));
1750 return table;
1751 }
1752
create_slope_table_fastest(AsicType asic_type,unsigned step_multiplier,const MotorProfile & motor_profile)1753 MotorSlopeTable create_slope_table_fastest(AsicType asic_type, unsigned step_multiplier,
1754 const MotorProfile& motor_profile)
1755 {
1756 return create_slope_table_for_speed(motor_profile.slope, motor_profile.slope.max_speed_w,
1757 motor_profile.step_type,
1758 step_multiplier, 2 * step_multiplier,
1759 get_slope_table_max_size(asic_type));
1760 }
1761
1762 /** @brief returns the lowest possible ydpi for the device
1763 * Parses device entry to find lowest motor dpi.
1764 * @param dev device description
1765 * @return lowest motor resolution
1766 */
sanei_genesys_get_lowest_ydpi(Genesys_Device * dev)1767 int sanei_genesys_get_lowest_ydpi(Genesys_Device *dev)
1768 {
1769 const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method);
1770 return resolution_settings.get_min_resolution_y();
1771 }
1772
1773 /** @brief returns the lowest possible dpi for the device
1774 * Parses device entry to find lowest motor or sensor dpi.
1775 * @param dev device description
1776 * @return lowest motor resolution
1777 */
sanei_genesys_get_lowest_dpi(Genesys_Device * dev)1778 int sanei_genesys_get_lowest_dpi(Genesys_Device *dev)
1779 {
1780 const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method);
1781 return std::min(resolution_settings.get_min_resolution_x(),
1782 resolution_settings.get_min_resolution_y());
1783 }
1784
1785 /** @brief check is a cache entry may be used
1786 * Compares current settings with the cache entry and return
1787 * true if they are compatible.
1788 * A calibration cache is compatible if color mode and x dpi match the user
1789 * requested scan. In the case of CIS scanners, dpi isn't a criteria.
1790 * flatbed cache entries are considered too old and then expires if they
1791 * are older than the expiration time option, forcing calibration at least once
1792 * then given time. */
sanei_genesys_is_compatible_calibration(Genesys_Device * dev,const ScanSession & session,const Genesys_Calibration_Cache * cache,bool for_overwrite)1793 bool sanei_genesys_is_compatible_calibration(Genesys_Device* dev,
1794 const ScanSession& session,
1795 const Genesys_Calibration_Cache* cache,
1796 bool for_overwrite)
1797 {
1798 DBG_HELPER(dbg);
1799 #ifdef HAVE_SYS_TIME_H
1800 struct timeval time;
1801 #endif
1802
1803 bool compatible = true;
1804
1805 const auto& dev_params = session.params;
1806
1807 if (dev_params.scan_method != cache->params.scan_method) {
1808 dbg.vlog(DBG_io, "incompatible: scan_method %d vs. %d\n",
1809 static_cast<unsigned>(dev_params.scan_method),
1810 static_cast<unsigned>(cache->params.scan_method));
1811 compatible = false;
1812 }
1813
1814 if (dev_params.xres != cache->params.xres) {
1815 dbg.vlog(DBG_io, "incompatible: params.xres %d vs. %d\n",
1816 dev_params.xres, cache->params.xres);
1817 compatible = false;
1818 }
1819
1820 if (dev_params.yres != cache->params.yres) {
1821 // exposure depends on selected sensor and we select the sensor according to yres
1822 dbg.vlog(DBG_io, "incompatible: params.yres %d vs. %d\n",
1823 dev_params.yres, cache->params.yres);
1824 compatible = false;
1825 }
1826
1827 if (dev_params.channels != cache->params.channels) {
1828 // exposure depends on total number of pixels at least on gl841
1829 dbg.vlog(DBG_io, "incompatible: params.channels %d vs. %d\n",
1830 dev_params.channels, cache->params.channels);
1831 compatible = false;
1832 }
1833
1834 if (dev_params.startx != cache->params.startx) {
1835 // exposure depends on total number of pixels at least on gl841
1836 dbg.vlog(DBG_io, "incompatible: params.startx %d vs. %d\n",
1837 dev_params.startx, cache->params.startx);
1838 compatible = false;
1839 }
1840
1841 if (dev_params.pixels != cache->params.pixels) {
1842 // exposure depends on total number of pixels at least on gl841
1843 dbg.vlog(DBG_io, "incompatible: params.pixels %d vs. %d\n",
1844 dev_params.pixels, cache->params.pixels);
1845 compatible = false;
1846 }
1847
1848 if (!compatible)
1849 {
1850 DBG (DBG_proc, "%s: completed, non compatible cache\n", __func__);
1851 return false;
1852 }
1853
1854 /* a cache entry expires after after expiration time for non sheetfed scanners */
1855 /* this is not taken into account when overwriting cache entries */
1856 #ifdef HAVE_SYS_TIME_H
1857 if (!for_overwrite && dev->settings.expiration_time >=0)
1858 {
1859 gettimeofday(&time, nullptr);
1860 if ((time.tv_sec - cache->last_calibration > dev->settings.expiration_time*60)
1861 && !dev->model->is_sheetfed
1862 && (dev->settings.scan_method == ScanMethod::FLATBED))
1863 {
1864 DBG (DBG_proc, "%s: expired entry, non compatible cache\n", __func__);
1865 return false;
1866 }
1867 }
1868 #endif
1869
1870 return true;
1871 }
1872
1873 /** @brief build lookup table for digital enhancements
1874 * Function to build a lookup table (LUT), often
1875 used by scanners to implement brightness/contrast/gamma
1876 or by backends to speed binarization/thresholding
1877
1878 offset and slope inputs are -127 to +127
1879
1880 slope rotates line around central input/output val,
1881 0 makes horizontal line
1882
1883 pos zero neg
1884 . x . . x
1885 . x . . x
1886 out . x .xxxxxxxxxxx . x
1887 . x . . x
1888 ....x....... ............ .......x....
1889 in in in
1890
1891 offset moves line vertically, and clamps to output range
1892 0 keeps the line crossing the center of the table
1893
1894 high low
1895 . xxxxxxxx .
1896 . x .
1897 out x . x
1898 . . x
1899 ............ xxxxxxxx....
1900 in in
1901
1902 out_min/max provide bounds on output values,
1903 useful when building thresholding lut.
1904 0 and 255 are good defaults otherwise.
1905 * @param lut pointer where to store the generated lut
1906 * @param in_bits number of bits for in values
1907 * @param out_bits number of bits of out values
1908 * @param out_min minimal out value
1909 * @param out_max maximal out value
1910 * @param slope slope of the generated data
1911 * @param offset offset of the generated data
1912 */
sanei_genesys_load_lut(unsigned char * lut,int in_bits,int out_bits,int out_min,int out_max,int slope,int offset)1913 void sanei_genesys_load_lut(unsigned char* lut,
1914 int in_bits, int out_bits,
1915 int out_min, int out_max,
1916 int slope, int offset)
1917 {
1918 DBG_HELPER(dbg);
1919 int i, j;
1920 double shift, rise;
1921 int max_in_val = (1 << in_bits) - 1;
1922 int max_out_val = (1 << out_bits) - 1;
1923 uint8_t *lut_p8 = lut;
1924 uint16_t* lut_p16 = reinterpret_cast<std::uint16_t*>(lut);
1925
1926 /* slope is converted to rise per unit run:
1927 * first [-127,127] to [-.999,.999]
1928 * then to [-PI/4,PI/4] then [0,PI/2]
1929 * then take the tangent (T.O.A)
1930 * then multiply by the normal linear slope
1931 * because the table may not be square, i.e. 1024x256*/
1932 auto pi_4 = M_PI / 4.0;
1933 rise = std::tan(static_cast<double>(slope) / 128 * pi_4 + pi_4) * max_out_val / max_in_val;
1934
1935 /* line must stay vertically centered, so figure
1936 * out vertical offset at central input value */
1937 shift = static_cast<double>(max_out_val) / 2 - (rise * max_in_val / 2);
1938
1939 /* convert the user offset setting to scale of output
1940 * first [-127,127] to [-1,1]
1941 * then to [-max_out_val/2,max_out_val/2]*/
1942 shift += static_cast<double>(offset) / 127 * max_out_val / 2;
1943
1944 for (i = 0; i <= max_in_val; i++)
1945 {
1946 j = static_cast<int>(rise * i + shift);
1947
1948 /* cap data to required range */
1949 if (j < out_min)
1950 {
1951 j = out_min;
1952 }
1953 else if (j > out_max)
1954 {
1955 j = out_max;
1956 }
1957
1958 /* copy result according to bit depth */
1959 if (out_bits <= 8)
1960 {
1961 *lut_p8 = j;
1962 lut_p8++;
1963 }
1964 else
1965 {
1966 *lut_p16 = j;
1967 lut_p16++;
1968 }
1969 }
1970 }
1971
1972 } // namespace genesys
1973