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