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