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