1 /* sane - Scanner Access Now Easy.
2
3 Copyright (C) 2003 Oliver Rauch
4 Copyright (C) 2003, 2004 Henning Meier-Geinitz <henning@meier-geinitz.de>
5 Copyright (C) 2004 Gerhard Jaeger <gerhard@gjaeger.de>
6 Copyright (C) 2004-2013 Stéphane Voltz <stef.dev@free.fr>
7 Copyright (C) 2005 Philipp Schmid <philipp8288@web.de>
8 Copyright (C) 2005-2009 Pierre Willenbrock <pierre@pirsoft.dnsalias.org>
9 Copyright (C) 2006 Laurent Charpentier <laurent_pubs@yahoo.com>
10 Copyright (C) 2010 Chris Berry <s0457957@sms.ed.ac.uk> and Michael Rickmann <mrickma@gwdg.de>
11 for Plustek Opticbook 3600 support
12
13
14 This file is part of the SANE package.
15
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License as
18 published by the Free Software Foundation; either version 2 of the
19 License, or (at your option) any later version.
20
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with this program. If not, see <https://www.gnu.org/licenses/>.
28
29 As a special exception, the authors of SANE give permission for
30 additional uses of the libraries contained in this release of SANE.
31
32 The exception is that, if you link a SANE library with other files
33 to produce an executable, this does not by itself cause the
34 resulting executable to be covered by the GNU General Public
35 License. Your use of that executable is in no way restricted on
36 account of linking the SANE library code into it.
37
38 This exception does not, however, invalidate any other reasons why
39 the executable file might be covered by the GNU General Public
40 License.
41
42 If you submit changes to SANE to the maintainers to be included in
43 a subsequent release, you agree by submitting the changes that
44 those changes may be distributed with this exception intact.
45
46 If you write modifications of your own for SANE, it is your choice
47 whether to permit this exception to apply to your modifications.
48 If you do not wish that, delete this exception notice.
49 */
50
51 #define DEBUG_DECLARE_ONLY
52
53 #include "gl841.h"
54 #include "gl841_registers.h"
55 #include "test_settings.h"
56
57 #include <vector>
58
59 namespace genesys {
60 namespace gl841 {
61
62
63 static int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor,
64 const MotorProfile& profile,
65 float slope_dpi,
66 int start,
67 int used_pixels);
68
69 /*
70 * Set all registers to default values
71 * (function called only once at the beginning)
72 */
73 static void
gl841_init_registers(Genesys_Device * dev)74 gl841_init_registers (Genesys_Device * dev)
75 {
76 DBG_HELPER(dbg);
77
78 dev->reg.init_reg(0x01, 0x20);
79 if (dev->model->is_cis) {
80 dev->reg.find_reg(0x01).value |= REG_0x01_CISSET;
81 } else {
82 dev->reg.find_reg(0x01).value &= ~REG_0x01_CISSET;
83 }
84 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
85 dev->reg.init_reg(0x01, 0x82);
86 }
87
88 dev->reg.init_reg(0x02, 0x38);
89 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
90 dev->reg.init_reg(0x02, 0x10);
91 }
92
93 dev->reg.init_reg(0x03, 0x5f);
94 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
95 dev->reg.init_reg(0x03, 0x50);
96 }
97
98 dev->reg.init_reg(0x04, 0x10);
99 if (dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600) {
100 dev->reg.init_reg(0x04, 0x22);
101 } else if (dev->model->model_id == ModelId::CANON_LIDE_80) {
102 dev->reg.init_reg(0x04, 0x02);
103 }
104
105 const auto& sensor = sanei_genesys_find_sensor_any(dev);
106
107 dev->reg.init_reg(0x05, 0x00); // disable gamma, 24 clocks/pixel
108
109 sanei_genesys_set_dpihw(dev->reg, sensor.register_dpihw);
110
111 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
112 dev->reg.init_reg(0x05, 0x4c);
113 }
114
115 dev->reg.init_reg(0x06, 0x18);
116 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
117 dev->reg.init_reg(0x06, 0x38);
118 }
119 if (dev->model->model_id == ModelId::VISIONEER_STROBE_XP300 ||
120 dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_485 ||
121 dev->model->model_id == ModelId::DCT_DOCKETPORT_487 ||
122 dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_685 ||
123 dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600)
124 {
125 dev->reg.init_reg(0x06, 0xb8);
126 }
127
128 dev->reg.init_reg(0x07, 0x00);
129 dev->reg.init_reg(0x08, 0x00);
130
131 dev->reg.init_reg(0x09, 0x10);
132 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
133 dev->reg.init_reg(0x09, 0x11);
134 }
135 if (dev->model->model_id == ModelId::VISIONEER_STROBE_XP300 ||
136 dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_485 ||
137 dev->model->model_id == ModelId::DCT_DOCKETPORT_487 ||
138 dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_685 ||
139 dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600)
140 {
141 dev->reg.init_reg(0x09, 0x00);
142 }
143 dev->reg.init_reg(0x0a, 0x00);
144
145 // EXPR[0:15], EXPG[0:15], EXPB[0:15]: Exposure time settings
146 dev->reg.init_reg(0x10, 0x00); // SENSOR_DEF
147 dev->reg.init_reg(0x11, 0x00); // SENSOR_DEF
148 dev->reg.init_reg(0x12, 0x00); // SENSOR_DEF
149 dev->reg.init_reg(0x13, 0x00); // SENSOR_DEF
150 dev->reg.init_reg(0x14, 0x00); // SENSOR_DEF
151 dev->reg.init_reg(0x15, 0x00); // SENSOR_DEF
152 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
153 dev->reg.init_reg(0x10, 0x40);
154 dev->reg.init_reg(0x11, 0x00);
155 dev->reg.init_reg(0x12, 0x40);
156 dev->reg.init_reg(0x13, 0x00);
157 dev->reg.init_reg(0x14, 0x40);
158 dev->reg.init_reg(0x15, 0x00);
159 }
160
161 dev->reg.init_reg(0x16, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
162 dev->reg.init_reg(0x17, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
163 dev->reg.init_reg(0x18, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
164 dev->reg.init_reg(0x19, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
165 dev->reg.init_reg(0x1a, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
166 dev->reg.init_reg(0x1b, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
167 dev->reg.init_reg(0x1c, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
168 dev->reg.init_reg(0x1d, 0x01); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
169 dev->reg.init_reg(0x1e, 0xf0);
170 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
171 dev->reg.init_reg(0x1e, 0x10);
172 }
173 dev->reg.init_reg(0x1f, 0x01);
174 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
175 dev->reg.init_reg(0x1f, 0x04);
176 }
177 dev->reg.init_reg(0x20, 0x20);
178 dev->reg.init_reg(0x21, 0x01);
179 dev->reg.init_reg(0x22, 0x01);
180 dev->reg.init_reg(0x23, 0x01);
181 dev->reg.init_reg(0x24, 0x01);
182 dev->reg.init_reg(0x25, 0x00);
183 dev->reg.init_reg(0x26, 0x00);
184 dev->reg.init_reg(0x27, 0x00);
185 dev->reg.init_reg(0x29, 0xff);
186
187 dev->reg.init_reg(0x2c, 0x00);
188 dev->reg.init_reg(0x2d, 0x00);
189 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
190 dev->reg.init_reg(0x2c, sensor.full_resolution >> 8);
191 dev->reg.init_reg(0x2d, sensor.full_resolution & 0xff);
192 }
193 dev->reg.init_reg(0x2e, 0x80);
194 dev->reg.init_reg(0x2f, 0x80);
195
196 dev->reg.init_reg(0x30, 0x00);
197 dev->reg.init_reg(0x31, 0x00);
198 dev->reg.init_reg(0x32, 0x00);
199 dev->reg.init_reg(0x33, 0x00);
200 dev->reg.init_reg(0x34, 0x00);
201 dev->reg.init_reg(0x35, 0x00);
202 dev->reg.init_reg(0x36, 0x00);
203 dev->reg.init_reg(0x37, 0x00);
204 dev->reg.init_reg(0x38, 0x4f);
205 dev->reg.init_reg(0x39, 0xc1);
206 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
207 dev->reg.init_reg(0x31, 0x10);
208 dev->reg.init_reg(0x32, 0x15);
209 dev->reg.init_reg(0x33, 0x0e);
210 dev->reg.init_reg(0x34, 0x40);
211 dev->reg.init_reg(0x35, 0x00);
212 dev->reg.init_reg(0x36, 0x2a);
213 dev->reg.init_reg(0x37, 0x30);
214 dev->reg.init_reg(0x38, 0x2a);
215 dev->reg.init_reg(0x39, 0xf8);
216 }
217
218 dev->reg.init_reg(0x3d, 0x00);
219 dev->reg.init_reg(0x3e, 0x00);
220 dev->reg.init_reg(0x3f, 0x00);
221
222 dev->reg.init_reg(0x52, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
223 dev->reg.init_reg(0x53, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
224 dev->reg.init_reg(0x54, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
225 dev->reg.init_reg(0x55, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
226 dev->reg.init_reg(0x56, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
227 dev->reg.init_reg(0x57, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
228 dev->reg.init_reg(0x58, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
229 dev->reg.init_reg(0x59, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
230 dev->reg.init_reg(0x5a, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
231
232 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
233 dev->reg.init_reg(0x5d, 0x20);
234 dev->reg.init_reg(0x5e, 0x41);
235 dev->reg.init_reg(0x5f, 0x40);
236 dev->reg.init_reg(0x60, 0x00);
237 dev->reg.init_reg(0x61, 0x00);
238 dev->reg.init_reg(0x62, 0x00);
239 dev->reg.init_reg(0x63, 0x00);
240 dev->reg.init_reg(0x64, 0x00);
241 dev->reg.init_reg(0x65, 0x00);
242 dev->reg.init_reg(0x66, 0x00);
243 dev->reg.init_reg(0x67, 0x40);
244 dev->reg.init_reg(0x68, 0x40);
245 dev->reg.init_reg(0x69, 0x20);
246 dev->reg.init_reg(0x6a, 0x20);
247 dev->reg.init_reg(0x6c, 0x00);
248 dev->reg.init_reg(0x6d, 0x00);
249 dev->reg.init_reg(0x6e, 0x00);
250 dev->reg.init_reg(0x6f, 0x00);
251 } else {
252 for (unsigned addr = 0x5d; addr <= 0x6f; addr++) {
253 dev->reg.init_reg(addr, 0);
254 }
255 dev->reg.init_reg(0x5e, 0x02);
256 if (dev->model->model_id == ModelId::CANON_LIDE_60) {
257 dev->reg.init_reg(0x66, 0xff);
258 }
259 }
260
261 dev->reg.init_reg(0x70, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
262 dev->reg.init_reg(0x71, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
263 dev->reg.init_reg(0x72, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
264 dev->reg.init_reg(0x73, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
265
266 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
267 dev->reg.init_reg(0x74, 0x00);
268 dev->reg.init_reg(0x75, 0x01);
269 dev->reg.init_reg(0x76, 0xff);
270 dev->reg.init_reg(0x77, 0x00);
271 dev->reg.init_reg(0x78, 0x0f);
272 dev->reg.init_reg(0x79, 0xf0);
273 dev->reg.init_reg(0x7a, 0xf0);
274 dev->reg.init_reg(0x7b, 0x00);
275 dev->reg.init_reg(0x7c, 0x1e);
276 dev->reg.init_reg(0x7d, 0x11);
277 dev->reg.init_reg(0x7e, 0x00);
278 dev->reg.init_reg(0x7f, 0x50);
279 dev->reg.init_reg(0x80, 0x00);
280 dev->reg.init_reg(0x81, 0x00);
281 dev->reg.init_reg(0x82, 0x0f);
282 dev->reg.init_reg(0x83, 0x00);
283 dev->reg.init_reg(0x84, 0x0e);
284 dev->reg.init_reg(0x85, 0x00);
285 dev->reg.init_reg(0x86, 0x0d);
286 dev->reg.init_reg(0x87, 0x02);
287 dev->reg.init_reg(0x88, 0x00);
288 dev->reg.init_reg(0x89, 0x00);
289 } else {
290 for (unsigned addr = 0x74; addr <= 0x87; addr++) {
291 dev->reg.init_reg(addr, 0);
292 }
293 }
294
295 scanner_setup_sensor(*dev, sensor, dev->reg);
296
297 // set up GPIO
298 for (const auto& reg : dev->gpo.regs) {
299 dev->reg.set8(reg.address, reg.value);
300 }
301
302 if (dev->model->gpio_id == GpioId::CANON_LIDE_35) {
303 dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO18;
304 dev->reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17;
305 }
306
307 if (dev->model->gpio_id == GpioId::XP300) {
308 dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17;
309 }
310
311 if (dev->model->gpio_id == GpioId::DP685) {
312 /* REG_0x6B_GPO18 lights on green led */
313 dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17 | REG_0x6B_GPO18;
314 }
315
316 if (dev->model->model_id == ModelId::CANON_LIDE_80) {
317 // specific scanner settings, clock and gpio first
318 dev->interface->write_register(REG_0x6B, 0x0c);
319 dev->interface->write_register(0x06, 0x10);
320 dev->interface->write_register(REG_0x6E, 0x6d);
321 dev->interface->write_register(REG_0x6F, 0x80);
322 dev->interface->write_register(REG_0x6B, 0x0e);
323 dev->interface->write_register(REG_0x6C, 0x00);
324 dev->interface->write_register(REG_0x6D, 0x8f);
325 dev->interface->write_register(REG_0x6B, 0x0e);
326 dev->interface->write_register(REG_0x6B, 0x0e);
327 dev->interface->write_register(REG_0x6B, 0x0a);
328 dev->interface->write_register(REG_0x6B, 0x02);
329 dev->interface->write_register(REG_0x6B, 0x06);
330
331 dev->interface->write_0x8c(0x10, 0x94);
332 dev->interface->write_register(0x09, 0x10);
333
334 // FIXME: the following code originally changed 0x6b, but due to bug the 0x6c register was
335 // effectively changed. The current behavior matches the old code, but should probably be fixed.
336 dev->reg.find_reg(0x6c).value |= REG_0x6B_GPO18;
337 dev->reg.find_reg(0x6c).value &= ~REG_0x6B_GPO17;
338 }
339 }
340
gl841_set_lide80_fe(Genesys_Device * dev,uint8_t set)341 static void gl841_set_lide80_fe(Genesys_Device* dev, uint8_t set)
342 {
343 DBG_HELPER(dbg);
344
345 if (set == AFE_INIT) {
346 dev->frontend = dev->frontend_initial;
347
348 // BUG: the following code does not make sense. The addresses are different than AFE_SET
349 // case
350 dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
351 dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x01));
352 dev->interface->write_fe_register(0x06, dev->frontend.regs.get_value(0x02));
353 }
354
355 if (set == AFE_SET)
356 {
357 dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
358 dev->interface->write_fe_register(0x06, dev->frontend.regs.get_value(0x20));
359 dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x28));
360 }
361 }
362
363 // Set values of Analog Device type frontend
gl841_set_ad_fe(Genesys_Device * dev,uint8_t set)364 static void gl841_set_ad_fe(Genesys_Device* dev, uint8_t set)
365 {
366 DBG_HELPER(dbg);
367 int i;
368
369 if (dev->model->adc_id==AdcId::CANON_LIDE_80) {
370 gl841_set_lide80_fe(dev, set);
371 return;
372 }
373
374 if (set == AFE_INIT) {
375 dev->frontend = dev->frontend_initial;
376
377 // write them to analog frontend
378 dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
379
380 dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01));
381
382 for (i = 0; i < 6; i++) {
383 dev->interface->write_fe_register(0x02 + i, 0x00);
384 }
385 }
386 if (set == AFE_SET)
387 {
388 // write them to analog frontend
389 dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
390
391 dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01));
392
393 // Write fe 0x02 (red gain)
394 dev->interface->write_fe_register(0x02, dev->frontend.get_gain(0));
395
396 // Write fe 0x03 (green gain)
397 dev->interface->write_fe_register(0x03, dev->frontend.get_gain(1));
398
399 // Write fe 0x04 (blue gain)
400 dev->interface->write_fe_register(0x04, dev->frontend.get_gain(2));
401
402 // Write fe 0x05 (red offset)
403 dev->interface->write_fe_register(0x05, dev->frontend.get_offset(0));
404
405 // Write fe 0x06 (green offset)
406 dev->interface->write_fe_register(0x06, dev->frontend.get_offset(1));
407
408 // Write fe 0x07 (blue offset)
409 dev->interface->write_fe_register(0x07, dev->frontend.get_offset(2));
410 }
411 }
412
413 // Set values of analog frontend
set_fe(Genesys_Device * dev,const Genesys_Sensor & sensor,uint8_t set) const414 void CommandSetGl841::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const
415 {
416 DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" :
417 set == AFE_SET ? "set" :
418 set == AFE_POWER_SAVE ? "powersave" : "huh?");
419 (void) sensor;
420
421 /* Analog Device type frontend */
422 uint8_t frontend_type = dev->reg.find_reg(0x04).value & REG_0x04_FESET;
423
424 if (frontend_type == 0x02) {
425 gl841_set_ad_fe(dev, set);
426 return;
427 }
428
429 if (frontend_type != 0x00) {
430 throw SaneException("unsupported frontend type %d", frontend_type);
431 }
432
433 if (set == AFE_INIT) {
434 dev->frontend = dev->frontend_initial;
435
436 // reset only done on init
437 dev->interface->write_fe_register(0x04, 0x80);
438 }
439
440
441 if (set == AFE_POWER_SAVE)
442 {
443 dev->interface->write_fe_register(0x01, 0x02);
444 return;
445 }
446
447 /* todo : base this test on cfg reg3 or a CCD family flag to be created */
448 /*if (dev->model->ccd_type!=SensorId::CCD_HP2300 && dev->model->ccd_type!=SensorId::CCD_HP2400) */
449 {
450 dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00));
451 dev->interface->write_fe_register(0x02, dev->frontend.regs.get_value(0x02));
452 }
453
454 dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01));
455 dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x03));
456 dev->interface->write_fe_register(0x06, dev->frontend.reg2[0]);
457 dev->interface->write_fe_register(0x08, dev->frontend.reg2[1]);
458 dev->interface->write_fe_register(0x09, dev->frontend.reg2[2]);
459
460 for (unsigned i = 0; i < 3; i++) {
461 dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i));
462 dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i));
463 dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i));
464 }
465 }
466
467 // @brief turn off motor
gl841_init_motor_regs_off(Genesys_Register_Set * reg,unsigned int scan_lines)468 static void gl841_init_motor_regs_off(Genesys_Register_Set* reg, unsigned int scan_lines)
469 {
470 DBG_HELPER_ARGS(dbg, "scan_lines=%d", scan_lines);
471 unsigned int feedl;
472
473 feedl = 2;
474
475 reg->set8(0x3d, (feedl >> 16) & 0xf);
476 reg->set8(0x3e, (feedl >> 8) & 0xff);
477 reg->set8(0x3f, feedl & 0xff);
478 reg->find_reg(0x5e).value &= ~0xe0;
479
480 reg->set8(0x25, (scan_lines >> 16) & 0xf);
481 reg->set8(0x26, (scan_lines >> 8) & 0xff);
482 reg->set8(0x27, scan_lines & 0xff);
483
484 reg->set8(0x02, 0x00);
485
486 reg->set8(0x67, 0x3f);
487 reg->set8(0x68, 0x3f);
488
489 reg->set8(REG_STEPNO, 1);
490 reg->set8(REG_FASTNO, 1);
491
492 reg->set8(0x69, 1);
493 reg->set8(0x6a, 1);
494 reg->set8(0x5f, 1);
495 }
496
497 /** @brief write motor table frequency
498 * Write motor frequency data table.
499 * @param dev device to set up motor
500 * @param ydpi motor target resolution
501 */
gl841_write_freq(Genesys_Device * dev,unsigned int ydpi)502 static void gl841_write_freq(Genesys_Device* dev, unsigned int ydpi)
503 {
504 DBG_HELPER(dbg);
505 /**< fast table */
506 uint8_t tdefault[] = {0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76};
507 uint8_t t1200[] = {0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20};
508 uint8_t t300[] = {0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60};
509 uint8_t t150[] = {0x0c,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0x40,0x14,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x0c,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0x11,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x0c,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0x40,0xd4,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x0c,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0x11,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60};
510
511 uint8_t *table;
512
513 if(dev->model->motor_id == MotorId::CANON_LIDE_80) {
514 switch(ydpi)
515 {
516 case 3600:
517 case 1200:
518 table=t1200;
519 break;
520 case 900:
521 case 300:
522 table=t300;
523 break;
524 case 450:
525 case 150:
526 table=t150;
527 break;
528 default:
529 table=tdefault;
530 }
531 dev->interface->write_register(0x66, 0x00);
532 dev->interface->write_gamma(0x28, 0xc000, table, 128);
533 dev->interface->write_register(0x5b, 0x00);
534 dev->interface->write_register(0x5c, 0x00);
535 }
536 }
537
gl841_init_motor_regs_feed(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,unsigned int feed_steps,ScanFlag flags)538 static void gl841_init_motor_regs_feed(Genesys_Device* dev, const Genesys_Sensor& sensor,
539 Genesys_Register_Set* reg, unsigned int feed_steps,/*1/base_ydpi*/
540 ScanFlag flags)
541 {
542 DBG_HELPER_ARGS(dbg, "feed_steps=%d, flags=%x", feed_steps, static_cast<unsigned>(flags));
543 unsigned step_multiplier = 2;
544 int use_fast_fed = 0;
545 unsigned int feedl;
546 /*number of scan lines to add in a scan_lines line*/
547
548 {
549 std::vector<uint16_t> table;
550 table.resize(256, 0xffff);
551
552 scanner_send_slope_table(dev, sensor, 0, table);
553 scanner_send_slope_table(dev, sensor, 1, table);
554 scanner_send_slope_table(dev, sensor, 2, table);
555 scanner_send_slope_table(dev, sensor, 3, table);
556 scanner_send_slope_table(dev, sensor, 4, table);
557 }
558
559 gl841_write_freq(dev, dev->motor.base_ydpi / 4);
560
561 // FIXME: use proper scan session
562 ScanSession session;
563 session.params.yres = dev->motor.base_ydpi;
564 session.params.scan_method = dev->model->default_method;
565
566 const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
567 if (fast_profile == nullptr) {
568 fast_profile = get_motor_profile_ptr(dev->motor.profiles, 0, session);
569 }
570 auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
571 *fast_profile);
572
573 // BUG: fast table is counted in base_ydpi / 4
574 feedl = feed_steps - fast_table.table.size() * 2;
575 use_fast_fed = 1;
576 if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
577 use_fast_fed = false;
578 }
579
580 reg->set8(0x3d, (feedl >> 16) & 0xf);
581 reg->set8(0x3e, (feedl >> 8) & 0xff);
582 reg->set8(0x3f, feedl & 0xff);
583 reg->find_reg(0x5e).value &= ~0xe0;
584
585 reg->set8(0x25, 0);
586 reg->set8(0x26, 0);
587 reg->set8(0x27, 0);
588
589 reg->find_reg(0x02).value &= ~0x01; /*LONGCURV OFF*/
590 reg->find_reg(0x02).value &= ~0x80; /*NOT_HOME OFF*/
591
592 reg->find_reg(0x02).value |= REG_0x02_MTRPWR;
593
594 if (use_fast_fed)
595 reg->find_reg(0x02).value |= 0x08;
596 else
597 reg->find_reg(0x02).value &= ~0x08;
598
599 if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
600 reg->find_reg(0x02).value |= 0x20;
601 } else {
602 reg->find_reg(0x02).value &= ~0x20;
603 }
604
605 reg->find_reg(0x02).value &= ~0x40;
606
607 if (has_flag(flags, ScanFlag::REVERSE)) {
608 reg->find_reg(0x02).value |= REG_0x02_MTRREV;
609 } else {
610 reg->find_reg(0x02).value &= ~REG_0x02_MTRREV;
611 }
612
613 scanner_send_slope_table(dev, sensor, 3, fast_table.table);
614
615 reg->set8(0x67, 0x3f);
616 reg->set8(0x68, 0x3f);
617 reg->set8(REG_STEPNO, 1);
618 reg->set8(REG_FASTNO, 1);
619 reg->set8(0x69, 1);
620 reg->set8(0x6a, fast_table.table.size() / step_multiplier);
621 reg->set8(0x5f, 1);
622 }
623
gl841_init_motor_regs_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,const ScanSession & session,Genesys_Register_Set * reg,const MotorProfile & motor_profile,unsigned int scan_exposure_time,unsigned scan_yres,unsigned int scan_lines,unsigned int scan_dummy,unsigned int feed_steps,ScanFlag flags)624 static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
625 const ScanSession& session,
626 Genesys_Register_Set* reg, const MotorProfile& motor_profile,
627 unsigned int scan_exposure_time,/*pixel*/
628 unsigned scan_yres, // dpi, motor resolution
629 unsigned int scan_lines,/*lines, scan resolution*/
630 unsigned int scan_dummy,
631 // number of scan lines to add in a scan_lines line
632 unsigned int feed_steps,/*1/base_ydpi*/
633 // maybe float for half/quarter step resolution?
634 ScanFlag flags)
635 {
636 DBG_HELPER_ARGS(dbg, "scan_exposure_time=%d, scan_yres=%d, scan_step_type=%d, scan_lines=%d,"
637 " scan_dummy=%d, feed_steps=%d, flags=%x",
638 scan_exposure_time, scan_yres, static_cast<unsigned>(motor_profile.step_type),
639 scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
640
641 unsigned step_multiplier = 2;
642
643 int use_fast_fed = 0;
644 unsigned int fast_time;
645 unsigned int slow_time;
646 unsigned int feedl;
647 unsigned int min_restep = 0x20;
648
649 /*
650 we calculate both tables for SCAN. the fast slope step count depends on
651 how many steps we need for slow acceleration and how much steps we are
652 allowed to use.
653 */
654
655 // At least in LiDE 50, 60 the fast movement table is counted in full steps.
656 const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
657 if (fast_profile == nullptr) {
658 fast_profile = &motor_profile;
659 }
660
661 auto slow_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres,
662 scan_exposure_time, step_multiplier, motor_profile);
663
664 if (feed_steps < (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type))) {
665 /*TODO: what should we do here?? go back to exposure calculation?*/
666 feed_steps = slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type);
667 }
668
669 auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
670 *fast_profile);
671
672 unsigned max_fast_slope_steps_count = step_multiplier;
673 if (feed_steps > (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)) + 2) {
674 max_fast_slope_steps_count = (feed_steps -
675 (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type))) / 2;
676 }
677
678 if (fast_table.table.size() > max_fast_slope_steps_count) {
679 fast_table.slice_steps(max_fast_slope_steps_count, step_multiplier);
680 }
681
682 /* fast fed special cases handling */
683 if (dev->model->gpio_id == GpioId::XP300
684 || dev->model->gpio_id == GpioId::DP685)
685 {
686 /* quirk: looks like at least this scanner is unable to use
687 2-feed mode */
688 use_fast_fed = 0;
689 }
690 else if (feed_steps < fast_table.table.size() * 2 +
691 (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
692 {
693 use_fast_fed = 0;
694 DBG(DBG_info, "%s: feed too short, slow move forced.\n", __func__);
695 } else {
696 /* for deciding whether we should use fast mode we need to check how long we
697 need for (fast)accelerating, moving, decelerating, (TODO: stopping?)
698 (slow)accelerating again versus (slow)accelerating and moving. we need
699 fast and slow tables here.
700 */
701 /*NOTE: scan_exposure_time is per scan_yres*/
702 /*NOTE: fast_exposure is per base_ydpi/4*/
703 /*we use full steps as base unit here*/
704 fast_time =
705 (fast_table.table.back() << static_cast<unsigned>(fast_profile->step_type)) / 4 *
706 (feed_steps - fast_table.table.size()*2 -
707 (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
708 + fast_table.pixeltime_sum() * 2 + slow_table.pixeltime_sum();
709 slow_time =
710 (scan_exposure_time * scan_yres) / dev->motor.base_ydpi *
711 (feed_steps - (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
712 + slow_table.pixeltime_sum();
713
714 use_fast_fed = fast_time < slow_time;
715 }
716
717 if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
718 use_fast_fed = false;
719 }
720
721 if (use_fast_fed) {
722 feedl = feed_steps - fast_table.table.size() * 2 -
723 (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type));
724 } else if ((feed_steps << static_cast<unsigned>(motor_profile.step_type)) < slow_table.table.size()) {
725 feedl = 0;
726 } else {
727 feedl = (feed_steps << static_cast<unsigned>(motor_profile.step_type)) - slow_table.table.size();
728 }
729 DBG(DBG_info, "%s: Decided to use %s mode\n", __func__, use_fast_fed?"fast feed":"slow feed");
730
731 reg->set8(0x3d, (feedl >> 16) & 0xf);
732 reg->set8(0x3e, (feedl >> 8) & 0xff);
733 reg->set8(0x3f, feedl & 0xff);
734 reg->find_reg(0x5e).value &= ~0xe0;
735 reg->set8(0x25, (scan_lines >> 16) & 0xf);
736 reg->set8(0x26, (scan_lines >> 8) & 0xff);
737 reg->set8(0x27, scan_lines & 0xff);
738 reg->find_reg(0x02).value = REG_0x02_MTRPWR;
739
740 if (has_flag(flags, ScanFlag::REVERSE)) {
741 reg->find_reg(0x02).value |= REG_0x02_MTRREV;
742 } else {
743 reg->find_reg(0x02).value &= ~REG_0x02_MTRREV;
744 }
745
746 if (use_fast_fed)
747 reg->find_reg(0x02).value |= 0x08;
748 else
749 reg->find_reg(0x02).value &= ~0x08;
750
751 if (has_flag(flags, ScanFlag::AUTO_GO_HOME))
752 reg->find_reg(0x02).value |= 0x20;
753 else
754 reg->find_reg(0x02).value &= ~0x20;
755
756 if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) {
757 reg->find_reg(0x02).value |= 0x40;
758 } else {
759 reg->find_reg(0x02).value &= ~0x40;
760 }
761
762 scanner_send_slope_table(dev, sensor, 0, slow_table.table);
763 scanner_send_slope_table(dev, sensor, 1, slow_table.table);
764 scanner_send_slope_table(dev, sensor, 2, slow_table.table);
765 scanner_send_slope_table(dev, sensor, 3, fast_table.table);
766 scanner_send_slope_table(dev, sensor, 4, fast_table.table);
767
768 gl841_write_freq(dev, scan_yres);
769
770 /* now reg 0x21 and 0x24 are available, we can calculate reg 0x22 and 0x23,
771 reg 0x60-0x62 and reg 0x63-0x65
772 rule:
773 2*STEPNO+FWDSTEP=2*FASTNO+BWDSTEP
774 */
775 /* steps of table 0*/
776 if (min_restep < slow_table.table.size() * 2 + 2) {
777 min_restep = slow_table.table.size() * 2 + 2;
778 }
779 /* steps of table 1*/
780 if (min_restep < slow_table.table.size() * 2 + 2) {
781 min_restep = slow_table.table.size() * 2 + 2;
782 }
783 /* steps of table 0*/
784 reg->set8(REG_FWDSTEP, min_restep - slow_table.table.size()*2);
785
786 /* steps of table 1*/
787 reg->set8(REG_BWDSTEP, min_restep - slow_table.table.size()*2);
788
789 /*
790 for z1/z2:
791 in dokumentation mentioned variables a-d:
792 a = time needed for acceleration, table 1
793 b = time needed for reg 0x1f... wouldn't that be reg0x1f*exposure_time?
794 c = time needed for acceleration, table 1
795 d = time needed for reg 0x22... wouldn't that be reg0x22*exposure_time?
796 z1 = (c+d-1) % exposure_time
797 z2 = (a+b-1) % exposure_time
798 */
799 /* i don't see any effect of this. i can only guess that this will enhance
800 sub-pixel accuracy
801 z1 = (slope_0_time-1) % exposure_time;
802 z2 = (slope_0_time-1) % exposure_time;
803 */
804 reg->set24(REG_0x60, 0);
805 reg->set24(REG_0x63, 0);
806 reg->find_reg(REG_0x1E).value &= REG_0x1E_WDTIME;
807 reg->find_reg(REG_0x1E).value |= scan_dummy;
808 reg->set8(0x67, 0x3f | (static_cast<unsigned>(motor_profile.step_type) << 6));
809 reg->set8(0x68, 0x3f | (static_cast<unsigned>(fast_profile->step_type) << 6));
810 reg->set8(REG_STEPNO, slow_table.table.size() / step_multiplier);
811 reg->set8(REG_FASTNO, slow_table.table.size() / step_multiplier);
812 reg->set8(0x69, slow_table.table.size() / step_multiplier);
813 reg->set8(0x6a, fast_table.table.size() / step_multiplier);
814 reg->set8(0x5f, fast_table.table.size() / step_multiplier);
815 }
816
gl841_init_optical_regs_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,unsigned int exposure_time,const ScanSession & session)817 static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
818 Genesys_Register_Set* reg, unsigned int exposure_time,
819 const ScanSession& session)
820 {
821 DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time);
822 uint16_t expavg, expr, expb, expg;
823
824 dev->cmd_set->set_fe(dev, sensor, AFE_SET);
825
826 /* gpio part.*/
827 if (dev->model->gpio_id == GpioId::CANON_LIDE_35) {
828 if (session.params.xres <= 600) {
829 reg->find_reg(REG_0x6C).value &= ~0x80;
830 } else {
831 reg->find_reg(REG_0x6C).value |= 0x80;
832 }
833 }
834 if (dev->model->gpio_id == GpioId::CANON_LIDE_80) {
835 if (session.params.xres <= 600) {
836 reg->find_reg(REG_0x6C).value &= ~0x40;
837 reg->find_reg(REG_0x6C).value |= 0x20;
838 } else {
839 reg->find_reg(REG_0x6C).value &= ~0x20;
840 reg->find_reg(REG_0x6C).value |= 0x40;
841 }
842 }
843
844 /* enable shading */
845 reg->find_reg(0x01).value |= REG_0x01_SCAN;
846 if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
847 has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION)) {
848 reg->find_reg(0x01).value &= ~REG_0x01_DVDSET;
849 } else {
850 reg->find_reg(0x01).value |= REG_0x01_DVDSET;
851 }
852
853 /* average looks better than deletion, and we are already set up to
854 use one of the average enabled resolutions
855 */
856 reg->find_reg(0x03).value |= REG_0x03_AVEENB;
857 sanei_genesys_set_lamp_power(dev, sensor, *reg,
858 !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
859
860 /* BW threshold */
861 reg->set8(0x2e, 0x7f);
862 reg->set8(0x2f, 0x7f);
863
864
865 /* monochrome / color scan */
866 switch (session.params.depth) {
867 case 8:
868 reg->find_reg(0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET);
869 break;
870 case 16:
871 reg->find_reg(0x04).value &= ~REG_0x04_LINEART;
872 reg->find_reg(0x04).value |= REG_0x04_BITSET;
873 break;
874 }
875
876 /* AFEMOD should depend on FESET, and we should set these
877 * bits separately */
878 reg->find_reg(0x04).value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
879 if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) {
880 reg->find_reg(0x04).value |= 0x10; /* no filter */
881 }
882 else if (session.params.channels == 1)
883 {
884 switch (session.params.color_filter)
885 {
886 case ColorFilter::RED:
887 reg->find_reg(0x04).value |= 0x14;
888 break;
889 case ColorFilter::GREEN:
890 reg->find_reg(0x04).value |= 0x18;
891 break;
892 case ColorFilter::BLUE:
893 reg->find_reg(0x04).value |= 0x1c;
894 break;
895 default:
896 reg->find_reg(0x04).value |= 0x10;
897 break;
898 }
899 }
900 else
901 {
902 if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) {
903 reg->find_reg(0x04).value |= 0x22; /* slow color pixel by pixel */
904 }
905 else
906 {
907 reg->find_reg(0x04).value |= 0x10; /* color pixel by pixel */
908 }
909 }
910
911 /* CIS scanners can do true gray by setting LEDADD */
912 reg->find_reg(0x87).value &= ~REG_0x87_LEDADD;
913 if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) {
914 reg->find_reg(0x87).value |= REG_0x87_LEDADD;
915 expr = reg->get16(REG_EXPR);
916 expg = reg->get16(REG_EXPG);
917 expb = reg->get16(REG_EXPB);
918
919 /* use minimal exposure for best image quality */
920 expavg = expg;
921 if (expr < expg)
922 expavg = expr;
923 if (expb < expavg)
924 expavg = expb;
925
926 dev->reg.set16(REG_EXPR, expavg);
927 dev->reg.set16(REG_EXPG, expavg);
928 dev->reg.set16(REG_EXPB, expavg);
929 }
930
931 // enable gamma tables
932 if (should_enable_gamma(session, sensor)) {
933 reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
934 } else {
935 reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB;
936 }
937
938 /* sensor parameters */
939 scanner_setup_sensor(*dev, sensor, dev->reg);
940 reg->set8(0x29, 255); /*<<<"magic" number, only suitable for cis*/
941 reg->set16(REG_DPISET, sensor.register_dpiset);
942 reg->set16(REG_STRPIXEL, session.pixel_startx);
943 reg->set16(REG_ENDPIXEL, session.pixel_endx);
944 reg->set24(REG_MAXWD, session.output_line_bytes);
945 reg->set16(REG_LPERIOD, exposure_time);
946 reg->set8(0x34, sensor.dummy_pixel);
947 }
948
949 static int
gl841_get_led_exposure(Genesys_Device * dev,const Genesys_Sensor & sensor)950 gl841_get_led_exposure(Genesys_Device * dev, const Genesys_Sensor& sensor)
951 {
952 int d,r,g,b,m;
953 if (!dev->model->is_cis)
954 return 0;
955 d = dev->reg.find_reg(0x19).value;
956
957 r = sensor.exposure.red;
958 g = sensor.exposure.green;
959 b = sensor.exposure.blue;
960
961 m = r;
962 if (m < g)
963 m = g;
964 if (m < b)
965 m = b;
966
967 return m + d;
968 }
969
970 /** @brief compute exposure time
971 * Compute exposure time for the device and the given scan resolution
972 */
gl841_exposure_time(Genesys_Device * dev,const Genesys_Sensor & sensor,const MotorProfile & profile,float slope_dpi,int start,int used_pixels)973 static int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor,
974 const MotorProfile& profile, float slope_dpi,
975 int start,
976 int used_pixels)
977 {
978 int led_exposure;
979
980 led_exposure=gl841_get_led_exposure(dev, sensor);
981 return sanei_genesys_exposure_time2(dev, profile, slope_dpi,
982 start + used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/
983 led_exposure);
984 }
985
init_regs_for_scan_session(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,const ScanSession & session) const986 void CommandSetGl841::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
987 Genesys_Register_Set* reg,
988 const ScanSession& session) const
989 {
990 DBG_HELPER(dbg);
991 session.assert_computed();
992
993 int move;
994 int exposure_time;
995
996 int slope_dpi = 0;
997 int dummy = 0;
998
999 /* dummy */
1000 /* dummy lines: may not be useful, for instance 250 dpi works with 0 or 1
1001 dummy line. Maybe the dummy line adds correctness since the motor runs
1002 slower (higher dpi)
1003 */
1004 /* for cis this creates better aligned color lines:
1005 dummy \ scanned lines
1006 0: R G B R ...
1007 1: R G B - R ...
1008 2: R G B - - R ...
1009 3: R G B - - - R ...
1010 4: R G B - - - - R ...
1011 5: R G B - - - - - R ...
1012 6: R G B - - - - - - R ...
1013 7: R G B - - - - - - - R ...
1014 8: R G B - - - - - - - - R ...
1015 9: R G B - - - - - - - - - R ...
1016 10: R G B - - - - - - - - - - R ...
1017 11: R G B - - - - - - - - - - - R ...
1018 12: R G B - - - - - - - - - - - - R ...
1019 13: R G B - - - - - - - - - - - - - R ...
1020 14: R G B - - - - - - - - - - - - - - R ...
1021 15: R G B - - - - - - - - - - - - - - - R ...
1022 -- pierre
1023 */
1024 dummy = 0;
1025
1026 /* slope_dpi */
1027 /* cis color scan is effectively a gray scan with 3 gray lines per color
1028 line and a FILTER of 0 */
1029 if (dev->model->is_cis) {
1030 slope_dpi = session.params.yres* session.params.channels;
1031 } else {
1032 slope_dpi = session.params.yres;
1033 }
1034
1035 slope_dpi = slope_dpi * (1 + dummy);
1036
1037 const auto& motor_profile = get_motor_profile(dev->motor.profiles, 0, session);
1038
1039 exposure_time = gl841_exposure_time(dev, sensor, motor_profile, slope_dpi,
1040 session.pixel_startx, session.optical_pixels);
1041
1042 gl841_init_optical_regs_scan(dev, sensor, reg, exposure_time, session);
1043
1044 move = session.params.starty;
1045
1046 /* subtract current head position */
1047 move -= (dev->head_pos(ScanHeadId::PRIMARY) * session.params.yres) / dev->motor.base_ydpi;
1048
1049 if (move < 0)
1050 move = 0;
1051
1052 /* round it */
1053 /* the move is not affected by dummy -- pierre */
1054 /* move = ((move + dummy) / (dummy + 1)) * (dummy + 1);*/
1055
1056 if (has_flag(session.params.flags, ScanFlag::SINGLE_LINE)) {
1057 gl841_init_motor_regs_off(reg, session.optical_line_count);
1058 } else {
1059 gl841_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure_time,
1060 slope_dpi, session.optical_line_count, dummy, move,
1061 session.params.flags);
1062 }
1063
1064 setup_image_pipeline(*dev, session);
1065
1066 dev->read_active = true;
1067
1068 dev->session = session;
1069
1070 dev->total_bytes_read = 0;
1071 dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines;
1072
1073 DBG(DBG_info, "%s: total bytes to send = %zu\n", __func__, dev->total_bytes_to_read);
1074 }
1075
calculate_scan_session(const Genesys_Device * dev,const Genesys_Sensor & sensor,const Genesys_Settings & settings) const1076 ScanSession CommandSetGl841::calculate_scan_session(const Genesys_Device* dev,
1077 const Genesys_Sensor& sensor,
1078 const Genesys_Settings& settings) const
1079 {
1080 DBG_HELPER(dbg);
1081 debug_dump(DBG_info, settings);
1082
1083 /* steps to move to reach scanning area:
1084 - first we move to physical start of scanning
1085 either by a fixed steps amount from the black strip
1086 or by a fixed amount from parking position,
1087 minus the steps done during shading calibration
1088 - then we move by the needed offset whitin physical
1089 scanning area
1090
1091 assumption: steps are expressed at maximum motor resolution
1092
1093 we need:
1094 float y_offset;
1095 float y_size;
1096 float y_offset_calib;
1097 mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH
1098 */
1099 float move = dev->model->y_offset;
1100 move += dev->settings.tl_y;
1101
1102 int move_dpi = dev->motor.base_ydpi;
1103 move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
1104
1105 float start = dev->model->x_offset;
1106 start += dev->settings.tl_x;
1107 start = static_cast<float>((start * dev->settings.xres) / MM_PER_INCH);
1108
1109 // we enable true gray for cis scanners only, and just when doing
1110 // scan since color calibration is OK for this mode
1111 ScanFlag flags = ScanFlag::NONE;
1112
1113 // true gray (led add for cis scanners)
1114 if (dev->model->is_cis && dev->settings.true_gray &&
1115 dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS &&
1116 dev->model->sensor_id != SensorId::CIS_CANON_LIDE_80)
1117 {
1118 // on Lide 80 the LEDADD bit results in only red LED array being lit
1119 flags |= ScanFlag::ENABLE_LEDADD;
1120 }
1121
1122 ScanSession session;
1123 session.params.xres = dev->settings.xres;
1124 session.params.yres = dev->settings.yres;
1125 session.params.startx = static_cast<unsigned>(start);
1126 session.params.starty = static_cast<unsigned>(move);
1127 session.params.pixels = dev->settings.pixels;
1128 session.params.requested_pixels = dev->settings.requested_pixels;
1129 session.params.lines = dev->settings.lines;
1130 session.params.depth = dev->settings.depth;
1131 session.params.channels = dev->settings.get_channels();
1132 session.params.scan_method = dev->settings.scan_method;
1133 session.params.scan_mode = dev->settings.scan_mode;
1134 session.params.color_filter = dev->settings.color_filter;
1135 session.params.flags = flags;
1136 compute_session(dev, session, sensor);
1137
1138 return session;
1139 }
1140
1141 // for fast power saving methods only, like disabling certain amplifiers
save_power(Genesys_Device * dev,bool enable) const1142 void CommandSetGl841::save_power(Genesys_Device* dev, bool enable) const
1143 {
1144 DBG_HELPER_ARGS(dbg, "enable = %d", enable);
1145
1146 const auto& sensor = sanei_genesys_find_sensor_any(dev);
1147
1148 if (enable)
1149 {
1150 if (dev->model->gpio_id == GpioId::CANON_LIDE_35)
1151 {
1152 /* expect GPIO17 to be enabled, and GPIO9 to be disabled,
1153 while GPIO8 is disabled*/
1154 /* final state: GPIO8 disabled, GPIO9 enabled, GPIO17 disabled,
1155 GPIO18 disabled*/
1156
1157 uint8_t val = dev->interface->read_register(REG_0x6D);
1158 dev->interface->write_register(REG_0x6D, val | 0x80);
1159
1160 dev->interface->sleep_ms(1);
1161
1162 /*enable GPIO9*/
1163 val = dev->interface->read_register(REG_0x6C);
1164 dev->interface->write_register(REG_0x6C, val | 0x01);
1165
1166 /*disable GPO17*/
1167 val = dev->interface->read_register(REG_0x6B);
1168 dev->interface->write_register(REG_0x6B, val & ~REG_0x6B_GPO17);
1169
1170 /*disable GPO18*/
1171 val = dev->interface->read_register(REG_0x6B);
1172 dev->interface->write_register(REG_0x6B, val & ~REG_0x6B_GPO18);
1173
1174 dev->interface->sleep_ms(1);
1175
1176 val = dev->interface->read_register(REG_0x6D);
1177 dev->interface->write_register(REG_0x6D, val & ~0x80);
1178
1179 }
1180 if (dev->model->gpio_id == GpioId::DP685)
1181 {
1182 uint8_t val = dev->interface->read_register(REG_0x6B);
1183 dev->interface->write_register(REG_0x6B, val & ~REG_0x6B_GPO17);
1184 dev->reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17;
1185 dev->initial_regs.find_reg(0x6b).value &= ~REG_0x6B_GPO17;
1186 }
1187
1188 set_fe(dev, sensor, AFE_POWER_SAVE);
1189
1190 }
1191 else
1192 {
1193 if (dev->model->gpio_id == GpioId::CANON_LIDE_35)
1194 {
1195 /* expect GPIO17 to be enabled, and GPIO9 to be disabled,
1196 while GPIO8 is disabled*/
1197 /* final state: GPIO8 enabled, GPIO9 disabled, GPIO17 enabled,
1198 GPIO18 enabled*/
1199
1200 uint8_t val = dev->interface->read_register(REG_0x6D);
1201 dev->interface->write_register(REG_0x6D, val | 0x80);
1202
1203 dev->interface->sleep_ms(10);
1204
1205 /*disable GPIO9*/
1206 val = dev->interface->read_register(REG_0x6C);
1207 dev->interface->write_register(REG_0x6C, val & ~0x01);
1208
1209 /*enable GPIO10*/
1210 val = dev->interface->read_register(REG_0x6C);
1211 dev->interface->write_register(REG_0x6C, val | 0x02);
1212
1213 /*enable GPO17*/
1214 val = dev->interface->read_register(REG_0x6B);
1215 dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO17);
1216 dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17;
1217 dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO17;
1218
1219 /*enable GPO18*/
1220 val = dev->interface->read_register(REG_0x6B);
1221 dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO18);
1222 dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO18;
1223 dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO18;
1224
1225 }
1226 if (dev->model->gpio_id == GpioId::DP665
1227 || dev->model->gpio_id == GpioId::DP685)
1228 {
1229 uint8_t val = dev->interface->read_register(REG_0x6B);
1230 dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO17);
1231 dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17;
1232 dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO17;
1233 }
1234
1235 }
1236 }
1237
set_powersaving(Genesys_Device * dev,int delay) const1238 void CommandSetGl841::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const
1239 {
1240 DBG_HELPER_ARGS(dbg, "delay = %d", delay);
1241 // FIXME: SEQUENTIAL not really needed in this case
1242 Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL);
1243 int rate, exposure_time, tgtime, time;
1244
1245 local_reg.init_reg(0x01, dev->reg.get8(0x01)); /* disable fastmode */
1246 local_reg.init_reg(0x03, dev->reg.get8(0x03)); /* Lamp power control */
1247 local_reg.init_reg(0x05, dev->reg.get8(0x05)); /*& ~REG_0x05_BASESEL*/; /* 24 clocks/pixel */
1248 local_reg.init_reg(0x18, 0x00); // Set CCD type
1249 local_reg.init_reg(0x38, 0x00);
1250 local_reg.init_reg(0x39, 0x00);
1251
1252 // period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE
1253 local_reg.init_reg(0x1c, dev->reg.get8(0x05) & ~REG_0x1C_TGTIME);
1254
1255 if (!delay) {
1256 local_reg.find_reg(0x03).value = local_reg.find_reg(0x03).value & 0xf0; /* disable lampdog and set lamptime = 0 */
1257 } else if (delay < 20) {
1258 local_reg.find_reg(0x03).value = (local_reg.find_reg(0x03).value & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */
1259 } else {
1260 local_reg.find_reg(0x03).value = (local_reg.find_reg(0x03).value & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */
1261 }
1262
1263 time = delay * 1000 * 60; /* -> msec */
1264 exposure_time = static_cast<std::uint32_t>(time * 32000.0 /
1265 (24.0 * 64.0 * (local_reg.find_reg(0x03).value & REG_0x03_LAMPTIM) *
1266 1024.0) + 0.5);
1267 /* 32000 = system clock, 24 = clocks per pixel */
1268 rate = (exposure_time + 65536) / 65536;
1269 if (rate > 4)
1270 {
1271 rate = 8;
1272 tgtime = 3;
1273 }
1274 else if (rate > 2)
1275 {
1276 rate = 4;
1277 tgtime = 2;
1278 }
1279 else if (rate > 1)
1280 {
1281 rate = 2;
1282 tgtime = 1;
1283 }
1284 else
1285 {
1286 rate = 1;
1287 tgtime = 0;
1288 }
1289
1290 local_reg.find_reg(0x1c).value |= tgtime;
1291 exposure_time /= rate;
1292
1293 if (exposure_time > 65535)
1294 exposure_time = 65535;
1295
1296 local_reg.set8(0x38, exposure_time >> 8);
1297 local_reg.set8(0x39, exposure_time & 255); /* lowbyte */
1298
1299 dev->interface->write_registers(local_reg);
1300 }
1301
gl841_get_paper_sensor(Genesys_Device * dev)1302 static bool gl841_get_paper_sensor(Genesys_Device* dev)
1303 {
1304 DBG_HELPER(dbg);
1305
1306 uint8_t val = dev->interface->read_register(REG_0x6D);
1307
1308 return (val & 0x1) == 0;
1309 }
1310
eject_document(Genesys_Device * dev) const1311 void CommandSetGl841::eject_document(Genesys_Device* dev) const
1312 {
1313 DBG_HELPER(dbg);
1314 Genesys_Register_Set local_reg;
1315 unsigned int init_steps;
1316 float feed_mm;
1317 int loop;
1318
1319 if (!dev->model->is_sheetfed) {
1320 DBG(DBG_proc, "%s: there is no \"eject sheet\"-concept for non sheet fed\n", __func__);
1321 return;
1322 }
1323
1324
1325 local_reg.clear();
1326
1327 // FIXME: unused result
1328 scanner_read_status(*dev);
1329 scanner_stop_action(*dev);
1330
1331 local_reg = dev->reg;
1332
1333 regs_set_optical_off(dev->model->asic_type, local_reg);
1334
1335 const auto& sensor = sanei_genesys_find_sensor_any(dev);
1336 gl841_init_motor_regs_feed(dev, sensor, &local_reg, 65536, ScanFlag::NONE);
1337
1338 dev->interface->write_registers(local_reg);
1339
1340 try {
1341 scanner_start_action(*dev, true);
1342 } catch (...) {
1343 catch_all_exceptions(__func__, [&]() { scanner_stop_action(*dev); });
1344 // restore original registers
1345 catch_all_exceptions(__func__, [&]()
1346 {
1347 dev->interface->write_registers(dev->reg);
1348 });
1349 throw;
1350 }
1351
1352 if (is_testing_mode()) {
1353 dev->interface->test_checkpoint("eject_document");
1354 scanner_stop_action(*dev);
1355 return;
1356 }
1357
1358 if (gl841_get_paper_sensor(dev)) {
1359 DBG(DBG_info, "%s: paper still loaded\n", __func__);
1360 /* force document TRUE, because it is definitely present */
1361 dev->document = true;
1362 dev->set_head_pos_zero(ScanHeadId::PRIMARY);
1363
1364 loop = 300;
1365 while (loop > 0) /* do not wait longer then 30 seconds */
1366 {
1367
1368 if (!gl841_get_paper_sensor(dev)) {
1369 DBG(DBG_info, "%s: reached home position\n", __func__);
1370 break;
1371 }
1372 dev->interface->sleep_ms(100);
1373 --loop;
1374 }
1375
1376 if (loop == 0)
1377 {
1378 // when we come here then the scanner needed too much time for this, so we better stop
1379 // the motor
1380 catch_all_exceptions(__func__, [&](){ scanner_stop_action(*dev); });
1381 throw SaneException(SANE_STATUS_IO_ERROR,
1382 "timeout while waiting for scanhead to go home");
1383 }
1384 }
1385
1386 feed_mm = dev->model->eject_feed;
1387 if (dev->document) {
1388 feed_mm += dev->model->post_scan;
1389 }
1390
1391 sanei_genesys_read_feed_steps(dev, &init_steps);
1392
1393 /* now feed for extra <number> steps */
1394 loop = 0;
1395 while (loop < 300) /* do not wait longer then 30 seconds */
1396 {
1397 unsigned int steps;
1398
1399 sanei_genesys_read_feed_steps(dev, &steps);
1400
1401 DBG(DBG_info, "%s: init_steps: %d, steps: %d\n", __func__, init_steps, steps);
1402
1403 if (steps > init_steps + (feed_mm * dev->motor.base_ydpi) / MM_PER_INCH)
1404 {
1405 break;
1406 }
1407
1408 dev->interface->sleep_ms(100);
1409 ++loop;
1410 }
1411
1412 scanner_stop_action(*dev);
1413
1414 dev->document = false;
1415 }
1416
update_home_sensor_gpio(Genesys_Device & dev) const1417 void CommandSetGl841::update_home_sensor_gpio(Genesys_Device& dev) const
1418 {
1419 if (dev.model->gpio_id == GpioId::CANON_LIDE_35) {
1420 dev.interface->read_register(REG_0x6C);
1421 dev.interface->write_register(REG_0x6C, dev.gpo.regs.get_value(0x6c));
1422 }
1423 if (dev.model->gpio_id == GpioId::CANON_LIDE_80) {
1424 dev.interface->read_register(REG_0x6B);
1425 dev.interface->write_register(REG_0x6B, REG_0x6B_GPO18 | REG_0x6B_GPO17);
1426 }
1427 }
1428
load_document(Genesys_Device * dev) const1429 void CommandSetGl841::load_document(Genesys_Device* dev) const
1430 {
1431 DBG_HELPER(dbg);
1432 int loop = 300;
1433 while (loop > 0) /* do not wait longer then 30 seconds */
1434 {
1435 if (gl841_get_paper_sensor(dev)) {
1436 DBG(DBG_info, "%s: document inserted\n", __func__);
1437
1438 /* when loading OK, document is here */
1439 dev->document = true;
1440
1441 // give user some time to place document correctly
1442 dev->interface->sleep_ms(1000);
1443 break;
1444 }
1445 dev->interface->sleep_ms(100);
1446 --loop;
1447 }
1448
1449 if (loop == 0)
1450 {
1451 // when we come here then the user needed to much time for this
1452 throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for document");
1453 }
1454 }
1455
1456 /**
1457 * detects end of document and adjust current scan
1458 * to take it into account
1459 * used by sheetfed scanners
1460 */
detect_document_end(Genesys_Device * dev) const1461 void CommandSetGl841::detect_document_end(Genesys_Device* dev) const
1462 {
1463 DBG_HELPER(dbg);
1464 bool paper_loaded = gl841_get_paper_sensor(dev);
1465
1466 /* sheetfed scanner uses home sensor as paper present */
1467 if (dev->document && !paper_loaded) {
1468 DBG(DBG_info, "%s: no more document\n", __func__);
1469 dev->document = false;
1470
1471 /* we can't rely on total_bytes_to_read since the frontend
1472 * might have been slow to read data, so we re-evaluate the
1473 * amount of data to scan form the hardware settings
1474 */
1475 unsigned scanned_lines = 0;
1476 try {
1477 sanei_genesys_read_scancnt(dev, &scanned_lines);
1478 } catch (...) {
1479 dev->total_bytes_to_read = dev->total_bytes_read;
1480 throw;
1481 }
1482
1483 if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS && dev->model->is_cis) {
1484 scanned_lines /= 3;
1485 }
1486
1487 std::size_t output_lines = dev->session.output_line_count;
1488
1489 std::size_t offset_lines = static_cast<std::size_t>(
1490 (dev->model->post_scan / MM_PER_INCH) * dev->settings.yres);
1491
1492 std::size_t scan_end_lines = scanned_lines + offset_lines;
1493
1494 std::size_t remaining_lines = dev->get_pipeline_source().remaining_bytes() /
1495 dev->session.output_line_bytes_raw;
1496
1497 DBG(DBG_io, "%s: scanned_lines=%u\n", __func__, scanned_lines);
1498 DBG(DBG_io, "%s: scan_end_lines=%zu\n", __func__, scan_end_lines);
1499 DBG(DBG_io, "%s: output_lines=%zu\n", __func__, output_lines);
1500 DBG(DBG_io, "%s: remaining_lines=%zu\n", __func__, remaining_lines);
1501
1502 if (scan_end_lines > output_lines) {
1503 auto skip_lines = scan_end_lines - output_lines;
1504
1505 if (remaining_lines > skip_lines) {
1506 remaining_lines -= skip_lines;
1507 dev->get_pipeline_source().set_remaining_bytes(remaining_lines *
1508 dev->session.output_line_bytes_raw);
1509 dev->total_bytes_to_read -= skip_lines * dev->session.output_line_bytes_requested;
1510 }
1511 }
1512 }
1513 }
1514
1515 // Send the low-level scan command
1516 // todo : is this that useful ?
begin_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,bool start_motor) const1517 void CommandSetGl841::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
1518 Genesys_Register_Set* reg, bool start_motor) const
1519 {
1520 DBG_HELPER(dbg);
1521 (void) sensor;
1522 // FIXME: SEQUENTIAL not really needed in this case
1523 Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL);
1524 uint8_t val;
1525
1526 if (dev->model->gpio_id == GpioId::CANON_LIDE_80) {
1527 val = dev->interface->read_register(REG_0x6B);
1528 val = REG_0x6B_GPO18;
1529 dev->interface->write_register(REG_0x6B, val);
1530 }
1531
1532 if (dev->model->model_id == ModelId::CANON_LIDE_50 ||
1533 dev->model->model_id == ModelId::CANON_LIDE_60)
1534 {
1535 if (dev->session.params.yres >= 1200) {
1536 dev->interface->write_register(REG_0x6C, 0x82);
1537 } else {
1538 dev->interface->write_register(REG_0x6C, 0x02);
1539 }
1540 if (dev->session.params.yres >= 600) {
1541 dev->interface->write_register(REG_0x6B, 0x01);
1542 } else {
1543 dev->interface->write_register(REG_0x6B, 0x03);
1544 }
1545 }
1546
1547 if (dev->model->sensor_id != SensorId::CCD_PLUSTEK_OPTICPRO_3600) {
1548 local_reg.init_reg(0x03, reg->get8(0x03) | REG_0x03_LAMPPWR);
1549 } else {
1550 // TODO PLUSTEK_3600: why ??
1551 local_reg.init_reg(0x03, reg->get8(0x03));
1552 }
1553
1554 local_reg.init_reg(0x01, reg->get8(0x01) | REG_0x01_SCAN);
1555 local_reg.init_reg(0x0d, 0x01);
1556
1557 // scanner_start_action(dev, start_motor)
1558 if (start_motor) {
1559 local_reg.init_reg(0x0f, 0x01);
1560 } else {
1561 // do not start motor yet
1562 local_reg.init_reg(0x0f, 0x00);
1563 }
1564
1565 dev->interface->write_registers(local_reg);
1566
1567 dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
1568 }
1569
1570
1571 // Send the stop scan command
end_scan(Genesys_Device * dev,Genesys_Register_Set __sane_unused__ * reg,bool check_stop) const1572 void CommandSetGl841::end_scan(Genesys_Device* dev, Genesys_Register_Set __sane_unused__* reg,
1573 bool check_stop) const
1574 {
1575 DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop);
1576
1577 if (!dev->model->is_sheetfed) {
1578 scanner_stop_action(*dev);
1579 }
1580 }
1581
1582 // Moves the slider to the home (top) position slowly
move_back_home(Genesys_Device * dev,bool wait_until_home) const1583 void CommandSetGl841::move_back_home(Genesys_Device* dev, bool wait_until_home) const
1584 {
1585 scanner_move_back_home(*dev, wait_until_home);
1586 }
1587
1588 // init registers for shading calibration
init_regs_for_shading(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const1589 void CommandSetGl841::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
1590 Genesys_Register_Set& regs) const
1591 {
1592 DBG_HELPER(dbg);
1593
1594 unsigned channels = 3;
1595
1596 unsigned resolution = sensor.shading_resolution;
1597 const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
1598 dev->settings.scan_method);
1599
1600 unsigned calib_lines =
1601 static_cast<unsigned>(dev->model->y_size_calib_dark_white_mm * resolution / MM_PER_INCH);
1602 unsigned starty =
1603 static_cast<unsigned>(dev->model->y_offset_calib_dark_white_mm * dev->motor.base_ydpi / MM_PER_INCH);
1604 ScanSession session;
1605 session.params.xres = resolution;
1606 session.params.yres = resolution;
1607 session.params.startx = 0;
1608 session.params.starty = starty;
1609 session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
1610 session.params.lines = calib_lines;
1611 session.params.depth = 16;
1612 session.params.channels = channels;
1613 session.params.scan_method = dev->settings.scan_method;
1614 session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
1615 session.params.color_filter = dev->settings.color_filter;
1616 session.params.flags = ScanFlag::DISABLE_SHADING |
1617 ScanFlag::DISABLE_GAMMA;
1618 compute_session(dev, session, calib_sensor);
1619
1620 init_regs_for_scan_session(dev, calib_sensor, ®s, session);
1621
1622 dev->calib_session = session;
1623 }
1624
1625 // this function sends generic gamma table (ie linear ones) or the Sensor specific one if provided
send_gamma_table(Genesys_Device * dev,const Genesys_Sensor & sensor) const1626 void CommandSetGl841::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const
1627 {
1628 DBG_HELPER(dbg);
1629 int size;
1630
1631 size = 256;
1632
1633 /* allocate temporary gamma tables: 16 bits words, 3 channels */
1634 std::vector<uint8_t> gamma(size * 2 * 3);
1635
1636 sanei_genesys_generate_gamma_buffer(dev, sensor, 16, 65535, size, gamma.data());
1637
1638 dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3);
1639 }
1640
1641
1642 /* this function does the led calibration by scanning one line of the calibration
1643 area below scanner's top on white strip.
1644
1645 -needs working coarse/gain
1646 */
led_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const1647 SensorExposure CommandSetGl841::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
1648 Genesys_Register_Set& regs) const
1649 {
1650 return scanner_led_calibration(*dev, sensor, regs);
1651 }
1652
1653 /** @brief calibration for AD frontend devices
1654 * offset calibration assumes that the scanning head is on a black area
1655 * For LiDE80 analog frontend
1656 * 0x0003 : is gain and belongs to [0..63]
1657 * 0x0006 : is offset
1658 * We scan a line with no gain until average offset reaches the target
1659 */
ad_fe_offset_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs)1660 static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
1661 Genesys_Register_Set& regs)
1662 {
1663 DBG_HELPER(dbg);
1664 int average;
1665 int turn;
1666 int top;
1667 int bottom;
1668 int target;
1669
1670 /* don't impact 3600 behavior since we can't test it */
1671 if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) {
1672 return;
1673 }
1674
1675 unsigned resolution = sensor.shading_resolution;
1676
1677 const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3,
1678 dev->settings.scan_method);
1679
1680 unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
1681 ScanSession session;
1682 session.params.xres = resolution;
1683 session.params.yres = dev->settings.yres;
1684 session.params.startx = 0;
1685 session.params.starty = 0;
1686 session.params.pixels = num_pixels;
1687 session.params.lines = 1;
1688 session.params.depth = 8;
1689 session.params.channels = 3;
1690 session.params.scan_method = dev->settings.scan_method;
1691 session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
1692 session.params.color_filter = dev->settings.color_filter;
1693 session.params.flags = ScanFlag::DISABLE_SHADING |
1694 ScanFlag::DISABLE_GAMMA |
1695 ScanFlag::SINGLE_LINE |
1696 ScanFlag::IGNORE_STAGGER_OFFSET |
1697 ScanFlag::IGNORE_COLOR_OFFSET;
1698 compute_session(dev, session, calib_sensor);
1699
1700 dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, ®s, session);
1701
1702 // FIXME: we're reading twice as much data for no reason
1703 std::size_t total_size = session.output_line_bytes * 2;
1704 std::vector<uint8_t> line(total_size);
1705
1706 dev->frontend.set_gain(0, 0);
1707 dev->frontend.set_gain(1, 0);
1708 dev->frontend.set_gain(2, 0);
1709
1710 /* loop on scan until target offset is reached */
1711 turn=0;
1712 target=24;
1713 bottom=0;
1714 top=255;
1715 do {
1716 /* set up offset mid range */
1717 dev->frontend.set_offset(0, (top + bottom) / 2);
1718 dev->frontend.set_offset(1, (top + bottom) / 2);
1719 dev->frontend.set_offset(2, (top + bottom) / 2);
1720
1721 /* scan line */
1722 DBG(DBG_info, "%s: starting line reading\n", __func__);
1723 dev->interface->write_registers(regs);
1724 dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
1725 dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true);
1726
1727 if (is_testing_mode()) {
1728 dev->interface->test_checkpoint("ad_fe_offset_calibration");
1729 scanner_stop_action(*dev);
1730 return;
1731 }
1732
1733 sanei_genesys_read_data_from_scanner(dev, line.data(), total_size);
1734 scanner_stop_action(*dev);
1735 if (dbg_log_image_data()) {
1736 char fn[30];
1737 std::snprintf(fn, 30, "gl841_offset_%02d.tiff", turn);
1738 write_tiff_file(fn, line.data(), 8, 3, num_pixels, 1);
1739 }
1740
1741 /* search for minimal value */
1742 average=0;
1743 for (std::size_t i = 0; i < total_size; i++)
1744 {
1745 average += line[i];
1746 }
1747 average/=total_size;
1748 DBG(DBG_data, "%s: average=%d\n", __func__, average);
1749
1750 /* if min value is above target, the current value becomes the new top
1751 * else it is the new bottom */
1752 if(average>target)
1753 {
1754 top=(top+bottom)/2;
1755 }
1756 else
1757 {
1758 bottom=(top+bottom)/2;
1759 }
1760 turn++;
1761 } while ((top-bottom)>1 && turn < 100);
1762
1763 // FIXME: don't overwrite the calibrated values
1764 dev->frontend.set_offset(0, 0);
1765 dev->frontend.set_offset(1, 0);
1766 dev->frontend.set_offset(2, 0);
1767 DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
1768 dev->frontend.get_offset(0),
1769 dev->frontend.get_offset(1),
1770 dev->frontend.get_offset(2));
1771 }
1772
1773 /* this function does the offset calibration by scanning one line of the calibration
1774 area below scanner's top. There is a black margin and the remaining is white.
1775
1776 this function expects the slider to be where?
1777 */
offset_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const1778 void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
1779 Genesys_Register_Set& regs) const
1780 {
1781 DBG_HELPER(dbg);
1782 int off[3],offh[3],offl[3],off1[3],off2[3];
1783 int min1[3],min2[3];
1784 unsigned cmin[3],cmax[3];
1785 int turn;
1786 int mintgt = 0x400;
1787
1788 /* Analog Device fronted have a different calibration */
1789 if ((dev->reg.find_reg(0x04).value & REG_0x04_FESET) == 0x02) {
1790 ad_fe_offset_calibration(dev, sensor, regs);
1791 return;
1792 }
1793
1794 /* offset calibration is always done in color mode */
1795 unsigned channels = 3;
1796
1797 unsigned resolution = sensor.shading_resolution;
1798
1799 const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
1800 dev->settings.scan_method);
1801
1802 ScanSession session;
1803 session.params.xres = resolution;
1804 session.params.yres = dev->settings.yres;
1805 session.params.startx = 0;
1806 session.params.starty = 0;
1807 session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
1808 session.params.lines = 1;
1809 session.params.depth = 16;
1810 session.params.channels = channels;
1811 session.params.scan_method = dev->settings.scan_method;
1812 session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
1813 session.params.color_filter = dev->settings.color_filter;
1814 session.params.flags = ScanFlag::DISABLE_SHADING |
1815 ScanFlag::DISABLE_GAMMA |
1816 ScanFlag::SINGLE_LINE |
1817 ScanFlag::IGNORE_STAGGER_OFFSET |
1818 ScanFlag::IGNORE_COLOR_OFFSET |
1819 ScanFlag::DISABLE_LAMP;
1820 compute_session(dev, session, calib_sensor);
1821
1822 init_regs_for_scan_session(dev, calib_sensor, ®s, session);
1823
1824 /* scan first line of data with no offset nor gain */
1825 /*WM8199: gain=0.73; offset=-260mV*/
1826 /*okay. the sensor black level is now at -260mV. we only get 0 from AFE...*/
1827 /* we should probably do real calibration here:
1828 * -detect acceptable offset with binary search
1829 * -calculate offset from this last version
1830 *
1831 * acceptable offset means
1832 * - few completely black pixels(<10%?)
1833 * - few completely white pixels(<10%?)
1834 *
1835 * final offset should map the minimum not completely black
1836 * pixel to 0(16 bits)
1837 *
1838 * this does account for dummy pixels at the end of ccd
1839 * this assumes slider is at black strip(which is not quite as black as "no
1840 * signal").
1841 *
1842 */
1843 dev->frontend.set_gain(0, 0);
1844 dev->frontend.set_gain(1, 0);
1845 dev->frontend.set_gain(2, 0);
1846 offh[0] = 0xff;
1847 offh[1] = 0xff;
1848 offh[2] = 0xff;
1849 offl[0] = 0x00;
1850 offl[1] = 0x00;
1851 offl[2] = 0x00;
1852 turn = 0;
1853
1854 Image first_line;
1855
1856 bool acceptable = false;
1857 do {
1858
1859 dev->interface->write_registers(regs);
1860
1861 for (unsigned j = 0; j < channels; j++) {
1862 off[j] = (offh[j]+offl[j])/2;
1863 dev->frontend.set_offset(j, off[j]);
1864 }
1865
1866 dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
1867
1868 DBG(DBG_info, "%s: starting first line reading\n", __func__);
1869 dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true);
1870
1871 if (is_testing_mode()) {
1872 dev->interface->test_checkpoint("offset_calibration");
1873 return;
1874 }
1875
1876 first_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
1877
1878 if (dbg_log_image_data()) {
1879 char fn[30];
1880 std::snprintf(fn, 30, "gl841_offset1_%02d.tiff", turn);
1881 write_tiff_file(fn, first_line);
1882 }
1883
1884 acceptable = true;
1885
1886 for (unsigned ch = 0; ch < channels; ch++) {
1887 cmin[ch] = 0;
1888 cmax[ch] = 0;
1889
1890 for (std::size_t x = 0; x < first_line.get_width(); x++) {
1891 auto value = first_line.get_raw_channel(x, 0, ch);
1892 if (value < 10) {
1893 cmin[ch]++;
1894 }
1895 if (value > 65525) {
1896 cmax[ch]++;
1897 }
1898 }
1899
1900 /* TODO the DP685 has a black strip in the middle of the sensor
1901 * should be handled in a more elegant way , could be a bug */
1902 if (dev->model->sensor_id == SensorId::CCD_DP685) {
1903 cmin[ch] -= 20;
1904 }
1905
1906 if (cmin[ch] > first_line.get_width() / 100) {
1907 acceptable = false;
1908 if (dev->model->is_cis)
1909 offl[0] = off[0];
1910 else
1911 offl[ch] = off[ch];
1912 }
1913 if (cmax[ch] > first_line.get_width() / 100) {
1914 acceptable = false;
1915 if (dev->model->is_cis)
1916 offh[0] = off[0];
1917 else
1918 offh[ch] = off[ch];
1919 }
1920 }
1921
1922 DBG(DBG_info,"%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0],
1923 cmin[1], cmax[1], cmin[2], cmax[2]);
1924
1925 if (dev->model->is_cis) {
1926 offh[2] = offh[1] = offh[0];
1927 offl[2] = offl[1] = offl[0];
1928 }
1929
1930 scanner_stop_action(*dev);
1931
1932 turn++;
1933 } while (!acceptable && turn < 100);
1934
1935 DBG(DBG_info,"%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]);
1936
1937
1938 for (unsigned ch = 0; ch < channels; ch++) {
1939 off1[ch] = off[ch];
1940
1941 min1[ch] = 65536;
1942
1943 for (std::size_t x = 0; x < first_line.get_width(); x++) {
1944 auto value = first_line.get_raw_channel(x, 0, ch);
1945
1946 if (min1[ch] > value && value >= 10) {
1947 min1[ch] = value;
1948 }
1949 }
1950 }
1951
1952
1953 offl[0] = off[0];
1954 offl[1] = off[0];
1955 offl[2] = off[0];
1956 turn = 0;
1957
1958 Image second_line;
1959 do {
1960
1961 for (unsigned j=0; j < channels; j++) {
1962 off[j] = (offh[j]+offl[j])/2;
1963 dev->frontend.set_offset(j, off[j]);
1964 }
1965
1966 dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
1967
1968 DBG(DBG_info, "%s: starting second line reading\n", __func__);
1969 dev->interface->write_registers(regs);
1970 dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true);
1971 second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
1972
1973 if (dbg_log_image_data()) {
1974 char fn[30];
1975 std::snprintf(fn, 30, "gl841_offset2_%02d.tiff", turn);
1976 write_tiff_file(fn, second_line);
1977 }
1978
1979 acceptable = true;
1980
1981 for (unsigned ch = 0; ch < channels; ch++) {
1982 cmin[ch] = 0;
1983 cmax[ch] = 0;
1984
1985 for (std::size_t x = 0; x < second_line.get_width(); x++) {
1986 auto value = second_line.get_raw_channel(x, 0, ch);
1987
1988 if (value < 10) {
1989 cmin[ch]++;
1990 }
1991 if (value > 65525) {
1992 cmax[ch]++;
1993 }
1994 }
1995
1996 if (cmin[ch] > second_line.get_width() / 100) {
1997 acceptable = false;
1998 if (dev->model->is_cis)
1999 offl[0] = off[0];
2000 else
2001 offl[ch] = off[ch];
2002 }
2003 if (cmax[ch] > second_line.get_width() / 100) {
2004 acceptable = false;
2005 if (dev->model->is_cis)
2006 offh[0] = off[0];
2007 else
2008 offh[ch] = off[ch];
2009 }
2010 }
2011
2012 DBG(DBG_info, "%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0],
2013 cmin[1], cmax[1], cmin[2], cmax[2]);
2014
2015 if (dev->model->is_cis) {
2016 offh[2] = offh[1] = offh[0];
2017 offl[2] = offl[1] = offl[0];
2018 }
2019
2020 scanner_stop_action(*dev);
2021
2022 turn++;
2023
2024 } while (!acceptable && turn < 100);
2025
2026 DBG(DBG_info, "%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]);
2027
2028
2029 for (unsigned ch = 0; ch < channels; ch++) {
2030 off2[ch] = off[ch];
2031
2032 min2[ch] = 65536;
2033
2034 for (std::size_t x = 0; x < second_line.get_width(); x++) {
2035 auto value = second_line.get_raw_channel(x, 0, ch);
2036
2037 if (min2[ch] > value && value != 0) {
2038 min2[ch] = value;
2039 }
2040 }
2041 }
2042
2043 DBG(DBG_info, "%s: first set: %d/%d,%d/%d,%d/%d\n", __func__, off1[0], min1[0], off1[1], min1[1],
2044 off1[2], min1[2]);
2045
2046 DBG(DBG_info, "%s: second set: %d/%d,%d/%d,%d/%d\n", __func__, off2[0], min2[0], off2[1], min2[1],
2047 off2[2], min2[2]);
2048
2049 /*
2050 calculate offset for each channel
2051 based on minimal pixel value min1 at offset off1 and minimal pixel value min2
2052 at offset off2
2053
2054 to get min at off, values are linearly interpolated:
2055 min=real+off*fact
2056 min1=real+off1*fact
2057 min2=real+off2*fact
2058
2059 fact=(min1-min2)/(off1-off2)
2060 real=min1-off1*(min1-min2)/(off1-off2)
2061
2062 off=(min-min1+off1*(min1-min2)/(off1-off2))/((min1-min2)/(off1-off2))
2063
2064 off=(min*(off1-off2)+min1*off2-off1*min2)/(min1-min2)
2065
2066 */
2067 for (unsigned ch = 0; ch < channels; ch++) {
2068 if (min2[ch] - min1[ch] == 0) {
2069 /*TODO: try to avoid this*/
2070 DBG(DBG_warn, "%s: difference too small\n", __func__);
2071 if (mintgt * (off1[ch] - off2[ch]) + min1[ch] * off2[ch] - min2[ch] * off1[ch] >= 0) {
2072 off[ch] = 0x0000;
2073 } else {
2074 off[ch] = 0xffff;
2075 }
2076 } else {
2077 off[ch] = (mintgt * (off1[ch] - off2[ch]) + min1[ch] * off2[ch] - min2[ch] * off1[ch])/(min1[ch]-min2[ch]);
2078 }
2079 if (off[ch] > 255) {
2080 off[ch] = 255;
2081 }
2082 if (off[ch] < 0) {
2083 off[ch] = 0;
2084 }
2085 dev->frontend.set_offset(ch, off[ch]);
2086 }
2087
2088 DBG(DBG_info, "%s: final offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]);
2089
2090 if (dev->model->is_cis) {
2091 if (off[0] < off[1])
2092 off[0] = off[1];
2093 if (off[0] < off[2])
2094 off[0] = off[2];
2095 dev->frontend.set_offset(0, off[0]);
2096 dev->frontend.set_offset(1, off[0]);
2097 dev->frontend.set_offset(2, off[0]);
2098 }
2099
2100 if (channels == 1)
2101 {
2102 dev->frontend.set_offset(1, dev->frontend.get_offset(0));
2103 dev->frontend.set_offset(2, dev->frontend.get_offset(0));
2104 }
2105 }
2106
2107
2108 /* alternative coarse gain calibration
2109 this on uses the settings from offset_calibration and
2110 uses only one scanline
2111 */
2112 /*
2113 with offset and coarse calibration we only want to get our input range into
2114 a reasonable shape. the fine calibration of the upper and lower bounds will
2115 be done with shading.
2116 */
coarse_gain_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs,int dpi) const2117 void CommandSetGl841::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
2118 Genesys_Register_Set& regs, int dpi) const
2119 {
2120 scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
2121 }
2122
2123 // wait for lamp warmup by scanning the same line until difference
2124 // between 2 scans is below a threshold
init_regs_for_warmup(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * local_reg) const2125 void CommandSetGl841::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
2126 Genesys_Register_Set* local_reg) const
2127 {
2128 DBG_HELPER(dbg);
2129 int num_pixels = 4 * 300;
2130 *local_reg = dev->reg;
2131
2132 /* okay.. these should be defaults stored somewhere */
2133 dev->frontend.set_gain(0, 0);
2134 dev->frontend.set_gain(1, 0);
2135 dev->frontend.set_gain(2, 0);
2136 dev->frontend.set_offset(0, 0x80);
2137 dev->frontend.set_offset(1, 0x80);
2138 dev->frontend.set_offset(2, 0x80);
2139
2140 auto flags = ScanFlag::DISABLE_SHADING |
2141 ScanFlag::DISABLE_GAMMA |
2142 ScanFlag::SINGLE_LINE |
2143 ScanFlag::IGNORE_STAGGER_OFFSET |
2144 ScanFlag::IGNORE_COLOR_OFFSET;
2145 if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
2146 dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
2147 {
2148 flags |= ScanFlag::USE_XPA;
2149 }
2150
2151 ScanSession session;
2152 session.params.xres = sensor.full_resolution;
2153 session.params.yres = dev->settings.yres;
2154 session.params.startx = sensor.dummy_pixel;
2155 session.params.starty = 0;
2156 session.params.pixels = num_pixels;
2157 session.params.lines = 1;
2158 session.params.depth = dev->model->bpp_color_values.front();
2159 session.params.channels = 3;
2160 session.params.scan_method = dev->settings.scan_method;
2161 session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
2162 session.params.color_filter = dev->settings.color_filter;
2163 session.params.flags = flags;
2164
2165 compute_session(dev, session, sensor);
2166
2167 init_regs_for_scan_session(dev, sensor, local_reg, session);
2168 }
2169
2170 /*
2171 * initialize ASIC : registers, motor tables, and gamma tables
2172 * then ensure scanner's head is at home
2173 */
init(Genesys_Device * dev) const2174 void CommandSetGl841::init(Genesys_Device* dev) const
2175 {
2176 DBG_INIT();
2177 DBG_HELPER(dbg);
2178 sanei_genesys_asic_init(dev);
2179 }
2180
update_hardware_sensors(Genesys_Scanner * s) const2181 void CommandSetGl841::update_hardware_sensors(Genesys_Scanner* s) const
2182 {
2183 DBG_HELPER(dbg);
2184 /* do what is needed to get a new set of events, but try to not lose
2185 any of them.
2186 */
2187 uint8_t val;
2188
2189 if (s->dev->model->gpio_id == GpioId::CANON_LIDE_35
2190 || s->dev->model->gpio_id == GpioId::CANON_LIDE_80)
2191 {
2192 val = s->dev->interface->read_register(REG_0x6D);
2193 s->buttons[BUTTON_SCAN_SW].write((val & 0x01) == 0);
2194 s->buttons[BUTTON_FILE_SW].write((val & 0x02) == 0);
2195 s->buttons[BUTTON_EMAIL_SW].write((val & 0x04) == 0);
2196 s->buttons[BUTTON_COPY_SW].write((val & 0x08) == 0);
2197 }
2198
2199 if (s->dev->model->gpio_id == GpioId::XP300 ||
2200 s->dev->model->gpio_id == GpioId::DP665 ||
2201 s->dev->model->gpio_id == GpioId::DP685)
2202 {
2203 val = s->dev->interface->read_register(REG_0x6D);
2204
2205 s->buttons[BUTTON_PAGE_LOADED_SW].write((val & 0x01) == 0);
2206 s->buttons[BUTTON_SCAN_SW].write((val & 0x02) == 0);
2207 }
2208 }
2209
2210 /**
2211 * Send shading calibration data. The buffer is considered to always hold values
2212 * for all the channels.
2213 */
send_shading_data(Genesys_Device * dev,const Genesys_Sensor & sensor,uint8_t * data,int size) const2214 void CommandSetGl841::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
2215 uint8_t* data, int size) const
2216 {
2217 DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size);
2218 uint32_t length, x, pixels, i;
2219 uint8_t *ptr,*src;
2220
2221 /* old method if no SHDAREA */
2222 if ((dev->reg.find_reg(0x01).value & REG_0x01_SHDAREA) == 0) {
2223 // Note that this requires the sensor pixel offset to be exactly the same as to start
2224 // reading from dummy_pixel + 1 position.
2225 dev->interface->write_buffer(0x3c, 0x0000, data, size);
2226 return;
2227 }
2228
2229 /* data is whole line, we extract only the part for the scanned area */
2230 length = static_cast<std::uint32_t>(size / 3);
2231
2232 // turn pixel value into bytes 2x16 bits words
2233 pixels = dev->session.pixel_endx - dev->session.pixel_startx;
2234 pixels *= 4;
2235
2236 // shading pixel begin is start pixel minus start pixel during shading
2237 // calibration. Currently only cases handled are full and half ccd resolution.
2238 unsigned beginpixel = dev->session.params.startx * dev->session.optical_resolution /
2239 dev->session.params.xres;
2240 beginpixel *= 4;
2241 beginpixel /= sensor.shading_factor;
2242
2243 dev->interface->record_key_value("shading_offset", std::to_string(beginpixel));
2244 dev->interface->record_key_value("shading_pixels", std::to_string(pixels));
2245 dev->interface->record_key_value("shading_length", std::to_string(length));
2246
2247 DBG(DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n", __func__, length,
2248 length/4);
2249 std::vector<uint8_t> buffer(pixels, 0);
2250
2251 /* write actual shading data contigously
2252 * channel by channel, starting at addr 0x0000
2253 * */
2254 for(i=0;i<3;i++)
2255 {
2256 /* copy data to work buffer and process it */
2257 /* coefficient destination */
2258 ptr=buffer.data();
2259
2260 /* iterate on both sensor segment, data has been averaged,
2261 * so is in the right order and we only have to copy it */
2262 for(x=0;x<pixels;x+=4)
2263 {
2264 /* coefficient source */
2265 src = data + x + beginpixel + i * length;
2266 ptr[0]=src[0];
2267 ptr[1]=src[1];
2268 ptr[2]=src[2];
2269 ptr[3]=src[3];
2270
2271 /* next shading coefficient */
2272 ptr+=4;
2273 }
2274
2275 // 0x5400 alignment for LIDE80 internal memory
2276 dev->interface->write_buffer(0x3c, 0x5400 * i, buffer.data(), pixels);
2277 }
2278 }
2279
needs_home_before_init_regs_for_scan(Genesys_Device * dev) const2280 bool CommandSetGl841::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
2281 {
2282 (void) dev;
2283 return true;
2284 }
2285
wait_for_motor_stop(Genesys_Device * dev) const2286 void CommandSetGl841::wait_for_motor_stop(Genesys_Device* dev) const
2287 {
2288 (void) dev;
2289 }
2290
asic_boot(Genesys_Device * dev,bool cold) const2291 void CommandSetGl841::asic_boot(Genesys_Device *dev, bool cold) const
2292 {
2293 // reset ASIC in case of cold boot
2294 if (cold) {
2295 dev->interface->write_register(0x0e, 0x01);
2296 dev->interface->write_register(0x0e, 0x00);
2297 }
2298
2299 gl841_init_registers(dev);
2300
2301 // Write initial registers
2302 dev->interface->write_registers(dev->reg);
2303
2304 // FIXME: 0x0b is not set, but on all other backends we do set it
2305 // dev->reg.remove_reg(0x0b);
2306
2307 if (dev->model->model_id == ModelId::CANON_LIDE_60) {
2308 dev->interface->write_0x8c(0x10, 0xa4);
2309 }
2310
2311 // FIXME: we probably don't need this
2312 const auto& sensor = sanei_genesys_find_sensor_any(dev);
2313 dev->cmd_set->set_fe(dev, sensor, AFE_INIT);
2314 }
2315
2316 } // namespace gl841
2317 } // namespace genesys
2318