1 /*  sane - Scanner Access Now Easy.
2 
3     Copyright (C) 2010-2013 Stéphane Voltz <stef.dev@free.fr>
4     Copyright (C) 2020 Povilas Kanapickas <povilas@radix.lt>
5 
6     This file is part of the SANE package.
7 
8     This program is free software; you can redistribute it and/or
9     modify it under the terms of the GNU General Public License as
10     published by the Free Software Foundation; either version 2 of the
11     License, or (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful, but
14     WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program.  If not, see <https://www.gnu.org/licenses/>.
20 
21     As a special exception, the authors of SANE give permission for
22     additional uses of the libraries contained in this release of SANE.
23 */
24 
25 #define DEBUG_DECLARE_ONLY
26 
27 #include "gl842_registers.h"
28 #include "gl842.h"
29 #include "test_settings.h"
30 
31 #include <string>
32 #include <vector>
33 
34 namespace genesys {
35 namespace gl842 {
36 
gl842_init_registers(Genesys_Device & dev)37 static void gl842_init_registers(Genesys_Device& dev)
38 {
39     // Within this function SENSOR_DEF marker documents that a register is part
40     // of the sensors definition and the actual value is set in
41     // gl842_setup_sensor().
42 
43     DBG_HELPER(dbg);
44 
45     dev.reg.clear();
46 
47     if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
48         dev.reg.init_reg(0x01, 0x00);
49         dev.reg.init_reg(0x02, 0x78);
50         dev.reg.init_reg(0x03, 0xbf);
51         dev.reg.init_reg(0x04, 0x22);
52         dev.reg.init_reg(0x05, 0x48);
53 
54         dev.reg.init_reg(0x06, 0xb8);
55 
56         dev.reg.init_reg(0x07, 0x00);
57         dev.reg.init_reg(0x08, 0x00);
58         dev.reg.init_reg(0x09, 0x00);
59         dev.reg.init_reg(0x0a, 0x00);
60         dev.reg.init_reg(0x0d, 0x01);
61     } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
62         dev.reg.init_reg(0x01, 0x82);
63         dev.reg.init_reg(0x02, 0x10);
64         dev.reg.init_reg(0x03, 0x60);
65         dev.reg.init_reg(0x04, 0x10);
66         dev.reg.init_reg(0x05, 0x8c);
67 
68         dev.reg.init_reg(0x06, 0x18);
69 
70         //dev.reg.init_reg(0x07, 0x00);
71         dev.reg.init_reg(0x08, 0x00);
72         dev.reg.init_reg(0x09, 0x21);
73         dev.reg.init_reg(0x0a, 0x00);
74         dev.reg.init_reg(0x0d, 0x00);
75     }
76 
77     dev.reg.init_reg(0x10, 0x00); // exposure, overwritten in scanner_setup_sensor() below
78     dev.reg.init_reg(0x11, 0x00); // exposure, overwritten in scanner_setup_sensor() below
79     dev.reg.init_reg(0x12, 0x00); // exposure, overwritten in scanner_setup_sensor() below
80     dev.reg.init_reg(0x13, 0x00); // exposure, overwritten in scanner_setup_sensor() below
81     dev.reg.init_reg(0x14, 0x00); // exposure, overwritten in scanner_setup_sensor() below
82     dev.reg.init_reg(0x15, 0x00); // exposure, overwritten in scanner_setup_sensor() below
83 
84     // CCD signal settings.
85     dev.reg.init_reg(0x16, 0x00); // SENSOR_DEF
86     dev.reg.init_reg(0x17, 0x00); // SENSOR_DEF
87     dev.reg.init_reg(0x18, 0x00); // SENSOR_DEF
88 
89     // EXPDMY[0:7]: Exposure time of dummy lines.
90     dev.reg.init_reg(0x19, 0x00); // SENSOR_DEF
91 
92     // Various CCD clock settings.
93     dev.reg.init_reg(0x1a, 0x00); // SENSOR_DEF
94     if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
95         dev.reg.init_reg(0x1b, 0x00); // SENSOR_DEF
96     }
97     dev.reg.init_reg(0x1c, 0x00); // SENSOR_DEF
98     dev.reg.init_reg(0x1d, 0x00); // SENSOR_DEF
99     dev.reg.init_reg(0x1e, 0x10); // WDTIME, LINESEL: setup during sensor and motor setup
100 
101     if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
102         dev.reg.init_reg(0x1f, 0x01);
103         dev.reg.init_reg(0x20, 0x27); // BUFSEL: buffer full condition
104     } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
105         dev.reg.init_reg(0x1f, 0x02);
106         dev.reg.init_reg(0x20, 0x02); // BUFSEL: buffer full condition
107     }
108 
109     dev.reg.init_reg(0x21, 0x10); // STEPNO: set during motor setup
110     dev.reg.init_reg(0x22, 0x10); // FWDSTEP: set during motor setup
111     dev.reg.init_reg(0x23, 0x10); // BWDSTEP: set during motor setup
112     dev.reg.init_reg(0x24, 0x10); // FASTNO: set during motor setup
113     dev.reg.init_reg(0x25, 0x00); // LINCNT: set during motor setup
114     dev.reg.init_reg(0x26, 0x00); // LINCNT: set during motor setup
115     dev.reg.init_reg(0x27, 0x00); // LINCNT: set during motor setup
116 
117     dev.reg.init_reg(0x29, 0xff); // LAMPPWM
118 
119     dev.reg.init_reg(0x2c, 0x02); // DPISET: set during sensor setup
120     dev.reg.init_reg(0x2d, 0x58); // DPISET: set during sensor setup
121 
122     dev.reg.init_reg(0x2e, 0x80); // BWHI: black/white low threshdold
123     dev.reg.init_reg(0x2f, 0x80); // BWLOW: black/white low threshold
124 
125     dev.reg.init_reg(0x30, 0x00); // STRPIXEL: set during sensor setup
126     dev.reg.init_reg(0x31, 0x49); // STRPIXEL: set during sensor setup
127     dev.reg.init_reg(0x32, 0x53); // ENDPIXEL: set during sensor setup
128     dev.reg.init_reg(0x33, 0xb9); // ENDPIXEL: set during sensor setup
129 
130     dev.reg.init_reg(0x34, 0x13); // DUMMY: SENSOR_DEF
131     dev.reg.init_reg(0x35, 0x00); // MAXWD: set during scan setup
132     dev.reg.init_reg(0x36, 0x40); // MAXWD: set during scan setup
133     dev.reg.init_reg(0x37, 0x00); // MAXWD: set during scan setup
134     dev.reg.init_reg(0x38, 0x2a); // LPERIOD: SENSOR_DEF
135     dev.reg.init_reg(0x39, 0xf8); // LPERIOD: SENSOR_DEF
136     dev.reg.init_reg(0x3d, 0x00); // FEEDL: set during motor setup
137     dev.reg.init_reg(0x3e, 0x00); // FEEDL: set during motor setup
138     dev.reg.init_reg(0x3f, 0x01); // FEEDL: set during motor setup
139 
140     dev.reg.init_reg(0x52, 0x00); // SENSOR_DEF
141     dev.reg.init_reg(0x53, 0x00); // SENSOR_DEF
142     dev.reg.init_reg(0x54, 0x00); // SENSOR_DEF
143     dev.reg.init_reg(0x55, 0x00); // SENSOR_DEF
144     dev.reg.init_reg(0x56, 0x00); // SENSOR_DEF
145     dev.reg.init_reg(0x57, 0x00); // SENSOR_DEF
146     dev.reg.init_reg(0x58, 0x00); // SENSOR_DEF
147     dev.reg.init_reg(0x59, 0x00); // SENSOR_DEF
148     dev.reg.init_reg(0x5a, 0x00); // SENSOR_DEF
149 
150     if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
151         dev.reg.init_reg(0x5e, 0x01); // DECSEL, STOPTIM
152     } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
153         dev.reg.init_reg(0x5e, 0x41); // DECSEL, STOPTIM
154         dev.reg.init_reg(0x5d, 0x20);
155     }
156     dev.reg.init_reg(0x5f, 0x10); // FMOVDEC: set during motor setup
157 
158     dev.reg.init_reg(0x60, 0x00); // Z1MOD: overwritten during motor setup
159     dev.reg.init_reg(0x61, 0x00); // Z1MOD: overwritten during motor setup
160     dev.reg.init_reg(0x62, 0x00); // Z1MOD: overwritten during motor setup
161     dev.reg.init_reg(0x63, 0x00); // Z2MOD: overwritten during motor setup
162     dev.reg.init_reg(0x64, 0x00); // Z2MOD: overwritten during motor setup
163     dev.reg.init_reg(0x65, 0x00); // Z2MOD: overwritten during motor setup
164 
165     if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
166         dev.reg.init_reg(0x67, 0x7f); // STEPSEL, MTRPWM: partially overwritten during motor setup
167         dev.reg.init_reg(0x68, 0x7f); // FSTPSEL, FASTPWM: partially overwritten during motor setup
168     } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
169         dev.reg.init_reg(0x66, 0x00); // PHFREQ
170         dev.reg.init_reg(0x67, 0x40); // STEPSEL, MTRPWM: partially overwritten during motor setup
171         dev.reg.init_reg(0x68, 0x40); // FSTPSEL, FASTPWM: partially overwritten during motor setup
172     }
173     dev.reg.init_reg(0x69, 0x10); // FSHDEC: overwritten during motor setup
174     dev.reg.init_reg(0x6a, 0x10); // FMOVNO: overwritten during motor setup
175 
176     // 0x6b, 0x6c, 0x6d, 0x6e, 0x6f - set according to gpio tables. See gl842_init_gpio.
177 
178     dev.reg.init_reg(0x70, 0x00); // SENSOR_DEF
179     dev.reg.init_reg(0x71, 0x00); // SENSOR_DEF
180     dev.reg.init_reg(0x72, 0x00); // SENSOR_DEF
181     dev.reg.init_reg(0x73, 0x00); // SENSOR_DEF
182     dev.reg.init_reg(0x74, 0x00); // SENSOR_DEF
183     dev.reg.init_reg(0x75, 0x00); // SENSOR_DEF
184     dev.reg.init_reg(0x76, 0x00); // SENSOR_DEF
185     dev.reg.init_reg(0x77, 0x00); // SENSOR_DEF
186     dev.reg.init_reg(0x78, 0x00); // SENSOR_DEF
187     dev.reg.init_reg(0x79, 0x00); // SENSOR_DEF
188     dev.reg.init_reg(0x7a, 0x00); // SENSOR_DEF
189     dev.reg.init_reg(0x7b, 0x00); // SENSOR_DEF
190     dev.reg.init_reg(0x7c, 0x00); // SENSOR_DEF
191     dev.reg.init_reg(0x7d, 0x00); // SENSOR_DEF
192 
193     // 0x7e - set according to gpio tables. See gl842_init_gpio.
194 
195     dev.reg.init_reg(0x7f, 0x00); // SENSOR_DEF
196 
197     // VRHOME, VRMOVE, VRBACK, VRSCAN: Vref settings of the motor driver IC for
198     // moving in various situations.
199     dev.reg.init_reg(0x80, 0x00); // MOTOR_PROFILE
200 
201     if (dev.model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
202         dev.reg.init_reg(0x81, 0x00);
203         dev.reg.init_reg(0x82, 0x00);
204         dev.reg.init_reg(0x83, 0x00);
205         dev.reg.init_reg(0x84, 0x00);
206         dev.reg.init_reg(0x85, 0x00);
207         dev.reg.init_reg(0x86, 0x00);
208         dev.reg.init_reg(0x87, 0x00);
209     } else if (dev.model->model_id == ModelId::CANON_LIDE_90) {
210         dev.reg.init_reg(0x7e, 0x00);
211         dev.reg.init_reg(0x81, 0x00);
212         dev.reg.init_reg(0x82, 0x0f);
213         dev.reg.init_reg(0x83, 0x00);
214         dev.reg.init_reg(0x84, 0x0e);
215         dev.reg.init_reg(0x85, 0x00);
216         dev.reg.init_reg(0x86, 0x0d);
217         dev.reg.init_reg(0x87, 0x00);
218         dev.reg.init_reg(0x88, 0x00);
219         dev.reg.init_reg(0x89, 0x00);
220     }
221 
222     const auto& sensor = sanei_genesys_find_sensor_any(&dev);
223     sanei_genesys_set_dpihw(dev.reg, sensor.register_dpihw);
224 
225     scanner_setup_sensor(dev, sensor, dev.reg);
226 }
227 
228 // Set values of analog frontend
set_fe(Genesys_Device * dev,const Genesys_Sensor & sensor,uint8_t set) const229 void CommandSetGl842::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const
230 {
231     DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" :
232                                set == AFE_SET ? "set" :
233                                set == AFE_POWER_SAVE ? "powersave" : "huh?");
234     (void) sensor;
235 
236     if (set == AFE_INIT) {
237         dev->frontend = dev->frontend_initial;
238     }
239 
240     // check analog frontend type
241     // FIXME: looks like we write to that register with initial data
242     uint8_t fe_type = dev->interface->read_register(REG_0x04) & REG_0x04_FESET;
243     if (fe_type == 2 || dev->model->model_id == ModelId::CANON_LIDE_90) {
244         for (const auto& reg : dev->frontend.regs) {
245             dev->interface->write_fe_register(reg.address, reg.value);
246         }
247         return;
248     }
249     if (fe_type != 0) {
250         throw SaneException(SANE_STATUS_UNSUPPORTED, "unsupported frontend type %d", fe_type);
251     }
252 
253     for (unsigned i = 1; i <= 3; i++) {
254         dev->interface->write_fe_register(i, dev->frontend.regs.get_value(0x00 + i));
255     }
256     for (const auto& reg : sensor.custom_fe_regs) {
257         dev->interface->write_fe_register(reg.address, reg.value);
258     }
259 
260     for (unsigned i = 0; i < 3; i++) {
261         dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i));
262     }
263 
264     for (unsigned i = 0; i < 3; i++) {
265         dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i));
266     }
267 }
268 
gl842_init_motor_regs_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,const ScanSession & session,Genesys_Register_Set * reg,const MotorProfile & motor_profile,unsigned int exposure,unsigned scan_yres,unsigned int scan_lines,unsigned int scan_dummy,unsigned int feed_steps,ScanFlag flags)269 static void gl842_init_motor_regs_scan(Genesys_Device* dev,
270                                        const Genesys_Sensor& sensor,
271                                        const ScanSession& session,
272                                        Genesys_Register_Set* reg,
273                                        const MotorProfile& motor_profile,
274                                        unsigned int exposure,
275                                        unsigned scan_yres,
276                                        unsigned int scan_lines,
277                                        unsigned int scan_dummy,
278                                        unsigned int feed_steps,
279                                        ScanFlag flags)
280 {
281     DBG_HELPER_ARGS(dbg, "exposure=%d, scan_yres=%d, step_type=%d, scan_lines=%d, scan_dummy=%d, "
282                          "feed_steps=%d, flags=%x",
283                     exposure, scan_yres, static_cast<unsigned>(motor_profile.step_type),
284                     scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags));
285 
286     unsigned step_multiplier = 2;
287     bool use_fast_fed = false;
288 
289     if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, ScanFlag::FEEDING))) {
290         use_fast_fed = true;
291     }
292     if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
293         use_fast_fed = false;
294     }
295 
296     reg->set24(REG_LINCNT, scan_lines);
297 
298     reg->set8(REG_0x02, 0);
299     sanei_genesys_set_motor_power(*reg, true);
300 
301     std::uint8_t reg02 = reg->get8(REG_0x02);
302     if (use_fast_fed) {
303         reg02 |= REG_0x02_FASTFED;
304     } else {
305         reg02 &= ~REG_0x02_FASTFED;
306     }
307 
308     // in case of automatic go home, move until home sensor
309     if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
310         reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
311     }
312 
313     // disable backtracking if needed
314     if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) ||
315         (scan_yres >= 2400) ||
316         (scan_yres >= sensor.full_resolution))
317     {
318         reg02 |= REG_0x02_ACDCDIS;
319     }
320 
321     if (has_flag(flags, ScanFlag::REVERSE)) {
322         reg02 |= REG_0x02_MTRREV;
323     } else {
324         reg02 &= ~REG_0x02_MTRREV;
325     }
326     reg->set8(REG_0x02, reg02);
327 
328     // scan and backtracking slope table
329     auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres, exposure,
330                                          step_multiplier, motor_profile);
331 
332     scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table);
333     scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table);
334     scanner_send_slope_table(dev, sensor, STOP_TABLE, scan_table.table);
335 
336     reg->set8(REG_STEPNO, scan_table.table.size() / step_multiplier);
337     reg->set8(REG_FASTNO, scan_table.table.size() / step_multiplier);
338     reg->set8(REG_FSHDEC, scan_table.table.size() / step_multiplier);
339 
340     // fast table
341     const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session);
342     if (fast_profile == nullptr) {
343         fast_profile = &motor_profile;
344     }
345 
346     auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier,
347                                                  *fast_profile);
348 
349     scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table);
350     scanner_send_slope_table(dev, sensor, HOME_TABLE, fast_table.table);
351 
352     reg->set8(REG_FMOVNO, fast_table.table.size() / step_multiplier);
353 
354     if (motor_profile.motor_vref != -1 && fast_profile->motor_vref != 1) {
355         std::uint8_t vref = 0;
356         vref |= (motor_profile.motor_vref << REG_0x80S_TABLE1_NORMAL) & REG_0x80_TABLE1_NORMAL;
357         vref |= (motor_profile.motor_vref << REG_0x80S_TABLE2_BACK) & REG_0x80_TABLE2_BACK;
358         vref |= (fast_profile->motor_vref << REG_0x80S_TABLE4_FAST) & REG_0x80_TABLE4_FAST;
359         vref |= (fast_profile->motor_vref << REG_0x80S_TABLE5_GO_HOME) & REG_0x80_TABLE5_GO_HOME;
360         reg->set8(REG_0x80, vref);
361     }
362 
363     // subtract acceleration distance from feedl
364     unsigned feedl = feed_steps;
365     feedl <<= static_cast<unsigned>(motor_profile.step_type);
366 
367     unsigned dist = scan_table.table.size() / step_multiplier;
368 
369     if (use_fast_fed) {
370         dist += (fast_table.table.size() / step_multiplier) * 2;
371     }
372 
373     // make sure when don't insane value : XXX STEF XXX in this case we should
374     // fall back to single table move
375     if (dist < feedl) {
376         feedl -= dist;
377     } else {
378         feedl = 1;
379     }
380 
381     reg->set24(REG_FEEDL, feedl);
382 
383     // doesn't seem to matter that much
384     std::uint32_t z1, z2;
385     sanei_genesys_calculate_zmod(use_fast_fed,
386                                  exposure,
387                                  scan_table.table,
388                                  scan_table.table.size() / step_multiplier,
389                                  feedl,
390                                  scan_table.table.size() / step_multiplier,
391                                  &z1,
392                                  &z2);
393     if (scan_yres > 600) {
394         z1 = 0;
395         z2 = 0;
396     }
397 
398     reg->set24(REG_Z1MOD, z1);
399     reg->set24(REG_Z2MOD, z2);
400 
401     reg->set8_mask(REG_0x1E, scan_dummy, 0x0f);
402 
403     reg->set8_mask(REG_0x67, static_cast<unsigned>(motor_profile.step_type) << REG_0x67S_STEPSEL,
404                    REG_0x67_STEPSEL);
405     reg->set8_mask(REG_0x68, static_cast<unsigned>(fast_profile->step_type) << REG_0x68S_FSTPSEL,
406                    REG_0x68_FSTPSEL);
407 
408     // steps for STOP table
409     reg->set8(REG_FMOVDEC, fast_table.table.size() / step_multiplier);
410 }
411 
gl842_init_optical_regs_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,unsigned int exposure,const ScanSession & session)412 static void gl842_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
413                                          Genesys_Register_Set* reg, unsigned int exposure,
414                                          const ScanSession& session)
415 {
416     DBG_HELPER(dbg);
417 
418     scanner_setup_sensor(*dev, sensor, *reg);
419 
420     dev->cmd_set->set_fe(dev, sensor, AFE_SET);
421 
422     // enable shading
423     regs_set_optical_off(dev->model->asic_type, *reg);
424     if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) ||
425         has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) ||
426         session.use_host_side_calib)
427     {
428         reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET;
429 
430     } else {
431         reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET;
432     }
433 
434     bool use_shdarea = true;
435 
436     if (use_shdarea) {
437         reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA;
438     } else {
439         reg->find_reg(REG_0x01).value &= ~REG_0x01_SHDAREA;
440     }
441 
442     if (dev->model->model_id == ModelId::CANON_8600F) {
443         reg->find_reg(REG_0x03).value |= REG_0x03_AVEENB;
444     } else {
445         reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB;
446     }
447 
448     // FIXME: we probably don't need to set exposure to registers at this point. It was this way
449     // before a refactor.
450     sanei_genesys_set_lamp_power(dev, sensor, *reg,
451                                  !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP));
452 
453     // select XPA
454     reg->find_reg(REG_0x03).value &= ~REG_0x03_XPASEL;
455     if (has_flag(session.params.flags, ScanFlag::USE_XPA)) {
456         reg->find_reg(REG_0x03).value |= REG_0x03_XPASEL;
457     }
458     reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA);
459 
460     // BW threshold
461     reg->set8(REG_0x2E, 0x7f);
462     reg->set8(REG_0x2F, 0x7f);
463 
464     // monochrome / color scan parameters
465     std::uint8_t reg04 = reg->get8(REG_0x04);
466     reg04 = reg04 & REG_0x04_FESET;
467 
468     switch (session.params.depth) {
469         case 8:
470             break;
471         case 16:
472             reg04 |= REG_0x04_BITSET;
473             break;
474     }
475 
476     if (session.params.channels == 1) {
477         switch (session.params.color_filter) {
478             case ColorFilter::RED: reg04 |= 0x14; break;
479             case ColorFilter::BLUE: reg04 |= 0x1c; break;
480             case ColorFilter::GREEN: reg04 |= 0x18; break;
481             default:
482                 break; // should not happen
483         }
484     } else {
485         switch (dev->frontend.layout.type) {
486             case FrontendType::WOLFSON:
487                 // pixel by pixel
488                 reg04 |= 0x10;
489                 break;
490             case FrontendType::ANALOG_DEVICES:
491                 // slow color pixel by pixel
492                 reg04 |= 0x20;
493                 break;
494             default:
495                 throw SaneException("Invalid frontend type %d",
496                                     static_cast<unsigned>(dev->frontend.layout.type));
497         }
498     }
499 
500     reg->set8(REG_0x04, reg04);
501 
502     const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution,
503                                                          session.params.channels,
504                                                          session.params.scan_method);
505     sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw);
506 
507     if (should_enable_gamma(session, sensor)) {
508         reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB;
509     } else {
510         reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB;
511     }
512 
513     reg->set16(REG_DPISET, sensor.register_dpiset);
514 
515     reg->set16(REG_STRPIXEL, session.pixel_startx);
516     reg->set16(REG_ENDPIXEL, session.pixel_endx);
517 
518     if (dev->model->is_cis) {
519         reg->set24(REG_MAXWD, session.output_line_bytes_raw * session.params.channels);
520     } else {
521         reg->set24(REG_MAXWD, session.output_line_bytes_raw);
522     }
523 
524     unsigned tgtime = exposure / 65536 + 1;
525     reg->set16(REG_LPERIOD, exposure / tgtime);
526 
527     reg->set8(REG_DUMMY, sensor.dummy_pixel);
528 }
529 
init_regs_for_scan_session(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,const ScanSession & session) const530 void CommandSetGl842::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor,
531                                                  Genesys_Register_Set* reg,
532                                                  const ScanSession& session) const
533 {
534     DBG_HELPER(dbg);
535     session.assert_computed();
536 
537     // we enable true gray for cis scanners only, and just when doing scan since color calibration
538     // is OK for this mode
539 
540     int dummy = 0;
541 
542   /* slope_dpi */
543   /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */
544     int slope_dpi = 0;
545     if (dev->model->is_cis) {
546         slope_dpi = session.params.yres * session.params.channels;
547     } else {
548         slope_dpi = session.params.yres;
549     }
550     slope_dpi = slope_dpi * (1 + dummy);
551 
552     int exposure = sensor.exposure_lperiod;
553     if (exposure < 0) {
554         throw std::runtime_error("Exposure not defined in sensor definition");
555     }
556     if (dev->model->model_id == ModelId::CANON_LIDE_90) {
557         exposure *= 2;
558     }
559     const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure, session);
560 
561     // now _LOGICAL_ optical values used are known, setup registers
562     gl842_init_optical_regs_scan(dev, sensor, reg, exposure, session);
563     gl842_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure, slope_dpi,
564                                session.optical_line_count, dummy, session.params.starty,
565                                session.params.flags);
566 
567     setup_image_pipeline(*dev, session);
568 
569     dev->read_active = true;
570 
571     dev->session = session;
572 
573     dev->total_bytes_read = 0;
574     dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines;
575 }
576 
calculate_scan_session(const Genesys_Device * dev,const Genesys_Sensor & sensor,const Genesys_Settings & settings) const577 ScanSession CommandSetGl842::calculate_scan_session(const Genesys_Device* dev,
578                                                     const Genesys_Sensor& sensor,
579                                                     const Genesys_Settings& settings) const
580 {
581     DBG_HELPER(dbg);
582     debug_dump(DBG_info, settings);
583 
584     ScanFlag flags = ScanFlag::NONE;
585 
586     float move = 0.0f;
587     if (settings.scan_method == ScanMethod::TRANSPARENCY ||
588         settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
589     {
590         // note: scanner_move_to_ta() function has already been called and the sensor is at the
591         // transparency adapter
592         if (!dev->ignore_offsets) {
593             move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta;
594         }
595         flags |= ScanFlag::USE_XPA;
596     } else {
597         if (!dev->ignore_offsets) {
598             move = dev->model->y_offset;
599         }
600     }
601 
602     move += settings.tl_y;
603 
604     int move_dpi = dev->motor.base_ydpi;
605     move = static_cast<float>((move * move_dpi) / MM_PER_INCH);
606 
607     float start = 0.0f;
608     if (settings.scan_method==ScanMethod::TRANSPARENCY ||
609         settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
610     {
611         start = dev->model->x_offset_ta;
612     } else {
613         start = dev->model->x_offset;
614     }
615     start = start + settings.tl_x;
616 
617     start = static_cast<float>((start * settings.xres) / MM_PER_INCH);
618 
619     ScanSession session;
620     session.params.xres = settings.xres;
621     session.params.yres = settings.yres;
622     session.params.startx = static_cast<unsigned>(start);
623     session.params.starty = static_cast<unsigned>(move);
624     session.params.pixels = settings.pixels;
625     session.params.requested_pixels = settings.requested_pixels;
626     session.params.lines = settings.lines;
627     session.params.depth = settings.depth;
628     session.params.channels = settings.get_channels();
629     session.params.scan_method = settings.scan_method;
630     session.params.scan_mode = settings.scan_mode;
631     session.params.color_filter = settings.color_filter;
632     session.params.flags = flags;
633     compute_session(dev, session, sensor);
634 
635     return session;
636 }
637 
save_power(Genesys_Device * dev,bool enable) const638 void CommandSetGl842::save_power(Genesys_Device* dev, bool enable) const
639 {
640     (void) dev;
641     DBG_HELPER_ARGS(dbg, "enable = %d", enable);
642 }
643 
set_powersaving(Genesys_Device * dev,int delay) const644 void CommandSetGl842::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const
645 {
646     (void) dev;
647     DBG_HELPER_ARGS(dbg, "delay = %d", delay);
648 }
649 
eject_document(Genesys_Device * dev) const650 void CommandSetGl842::eject_document(Genesys_Device* dev) const
651 {
652     (void) dev;
653     DBG_HELPER(dbg);
654 }
655 
656 
load_document(Genesys_Device * dev) const657 void CommandSetGl842::load_document(Genesys_Device* dev) const
658 {
659     DBG_HELPER(dbg);
660     (void) dev;
661 }
662 
detect_document_end(Genesys_Device * dev) const663 void CommandSetGl842::detect_document_end(Genesys_Device* dev) const
664 {
665     DBG_HELPER(dbg);
666     (void) dev;
667     throw SaneException(SANE_STATUS_UNSUPPORTED);
668 }
669 
670 // Send the low-level scan command
begin_scan(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg,bool start_motor) const671 void CommandSetGl842::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor,
672                                  Genesys_Register_Set* reg, bool start_motor) const
673 {
674     DBG_HELPER(dbg);
675     (void) sensor;
676 
677     if (reg->state.is_xpa_on && reg->state.is_lamp_on &&
678         !has_flag(dev->model->flags, ModelFlag::TA_NO_SECONDARY_LAMP))
679     {
680         dev->cmd_set->set_xpa_lamp_power(*dev, true);
681     }
682     if (reg->state.is_xpa_on && !has_flag(dev->model->flags, ModelFlag::UTA_NO_SECONDARY_MOTOR)) {
683         dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY);
684     }
685 
686     if (dev->model->model_id == ModelId::CANON_LIDE_90) {
687         if (has_flag(dev->session.params.flags, ScanFlag::REVERSE)) {
688             dev->interface->write_register(REG_0x6B, 0x01);
689             dev->interface->write_register(REG_0x6C, 0x02);
690         } else {
691             dev->interface->write_register(REG_0x6B, 0x03);
692             switch (dev->session.params.xres) {
693                 case 150: dev->interface->write_register(REG_0x6C, 0x74); break;
694                 case 300: dev->interface->write_register(REG_0x6C, 0x38); break;
695                 case 600: dev->interface->write_register(REG_0x6C, 0x1c); break;
696                 case 1200: dev->interface->write_register(REG_0x6C, 0x2c); break;
697                 case 2400: dev->interface->write_register(REG_0x6C, 0x0c); break;
698                 default:
699                     break;
700             }
701         }
702         dev->interface->sleep_ms(100);
703     }
704 
705     scanner_clear_scan_and_feed_counts(*dev);
706 
707     // enable scan and motor
708     std::uint8_t val = dev->interface->read_register(REG_0x01);
709     val |= REG_0x01_SCAN;
710     dev->interface->write_register(REG_0x01, val);
711 
712     scanner_start_action(*dev, start_motor);
713 
714     switch (reg->state.motor_mode) {
715         case MotorMode::PRIMARY: {
716             if (reg->state.is_motor_on) {
717                 dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
718             }
719             break;
720         }
721         case MotorMode::PRIMARY_AND_SECONDARY: {
722             if (reg->state.is_motor_on) {
723                 dev->advance_head_pos_by_session(ScanHeadId::PRIMARY);
724                 dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
725             }
726             break;
727         }
728         case MotorMode::SECONDARY: {
729             if (reg->state.is_motor_on) {
730                 dev->advance_head_pos_by_session(ScanHeadId::SECONDARY);
731             }
732             break;
733         }
734     }
735 }
736 
end_scan(Genesys_Device * dev,Genesys_Register_Set * reg,bool check_stop) const737 void CommandSetGl842::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg,
738                                bool check_stop) const
739 {
740     DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop);
741 
742     if (reg->state.is_xpa_on) {
743         dev->cmd_set->set_xpa_lamp_power(*dev, false);
744     }
745 
746     if (!dev->model->is_sheetfed) {
747         scanner_stop_action(*dev);
748     }
749 }
750 
move_back_home(Genesys_Device * dev,bool wait_until_home) const751 void CommandSetGl842::move_back_home(Genesys_Device* dev, bool wait_until_home) const
752 {
753     scanner_move_back_home(*dev, wait_until_home);
754 }
755 
init_regs_for_shading(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const756 void CommandSetGl842::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
757                                             Genesys_Register_Set& regs) const
758 {
759     DBG_HELPER(dbg);
760     int move;
761 
762     float calib_size_mm = 0;
763     if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
764         dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
765     {
766         calib_size_mm = dev->model->y_size_calib_ta_mm;
767     } else {
768         calib_size_mm = dev->model->y_size_calib_mm;
769     }
770 
771     unsigned resolution = sensor.shading_resolution;
772 
773     unsigned channels = 3;
774     const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
775                                                          dev->settings.scan_method);
776 
777     unsigned calib_pixels = 0;
778     unsigned calib_pixels_offset = 0;
779 
780     if (should_calibrate_only_active_area(*dev, dev->settings)) {
781         float offset = dev->model->x_offset_ta;
782         // FIXME: we should use resolution here
783         offset = static_cast<float>((offset * dev->settings.xres) / MM_PER_INCH);
784 
785         float size = dev->model->x_size_ta;
786         size = static_cast<float>((size * dev->settings.xres) / MM_PER_INCH);
787 
788         calib_pixels_offset = static_cast<std::size_t>(offset);
789         calib_pixels = static_cast<std::size_t>(size);
790     } else {
791         calib_pixels_offset = 0;
792         calib_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
793     }
794 
795     ScanFlag flags = ScanFlag::DISABLE_SHADING |
796                      ScanFlag::DISABLE_GAMMA |
797                      ScanFlag::DISABLE_BUFFER_FULL_MOVE;
798 
799     if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
800         dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
801     {
802         // note: scanner_move_to_ta() function has already been called and the sensor is at the
803         // transparency adapter
804         move = static_cast<int>(dev->model->y_offset_calib_white_ta -
805                                 dev->model->y_offset_sensor_to_ta);
806         flags |= ScanFlag::USE_XPA;
807     } else {
808         move = static_cast<int>(dev->model->y_offset_calib_white);
809     }
810 
811     move = static_cast<int>((move * resolution) / MM_PER_INCH);
812     unsigned calib_lines = static_cast<unsigned>(calib_size_mm * resolution / MM_PER_INCH);
813 
814     ScanSession session;
815     session.params.xres = resolution;
816     session.params.yres = resolution;
817     session.params.startx = calib_pixels_offset;
818     session.params.starty = move;
819     session.params.pixels = calib_pixels;
820     session.params.lines = calib_lines;
821     session.params.depth = 16;
822     session.params.channels = channels;
823     session.params.scan_method = dev->settings.scan_method;
824     session.params.scan_mode = dev->settings.scan_mode;
825     session.params.color_filter = dev->settings.color_filter;
826     session.params.flags = flags;
827     compute_session(dev, session, calib_sensor);
828 
829     init_regs_for_scan_session(dev, calib_sensor, &regs, session);
830 
831     dev->calib_session = session;
832 }
833 
send_gamma_table(Genesys_Device * dev,const Genesys_Sensor & sensor) const834 void CommandSetGl842::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const
835 {
836     DBG_HELPER(dbg);
837 
838     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200)
839         return; // No gamma on this model
840 
841     unsigned size = 256;
842 
843     std::vector<uint8_t> gamma(size * 2 * 3);
844 
845     std::vector<uint16_t> rgamma = get_gamma_table(dev, sensor, GENESYS_RED);
846     std::vector<uint16_t> ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN);
847     std::vector<uint16_t> bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE);
848 
849     // copy sensor specific's gamma tables
850     for (unsigned i = 0; i < size; i++) {
851         gamma[i * 2 + size * 0 + 0] = rgamma[i] & 0xff;
852         gamma[i * 2 + size * 0 + 1] = (rgamma[i] >> 8) & 0xff;
853         gamma[i * 2 + size * 2 + 0] = ggamma[i] & 0xff;
854         gamma[i * 2 + size * 2 + 1] = (ggamma[i] >> 8) & 0xff;
855         gamma[i * 2 + size * 4 + 0] = bgamma[i] & 0xff;
856         gamma[i * 2 + size * 4 + 1] = (bgamma[i] >> 8) & 0xff;
857     }
858 
859     dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3);
860 }
861 
led_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const862 SensorExposure CommandSetGl842::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
863                                                 Genesys_Register_Set& regs) const
864 {
865     return scanner_led_calibration(*dev, sensor, regs);
866 }
867 
offset_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs) const868 void CommandSetGl842::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
869                                          Genesys_Register_Set& regs) const
870 {
871     scanner_offset_calibration(*dev, sensor, regs);
872 }
873 
coarse_gain_calibration(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set & regs,int dpi) const874 void CommandSetGl842::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
875                                               Genesys_Register_Set& regs, int dpi) const
876 {
877     scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
878 }
879 
init_regs_for_warmup(Genesys_Device * dev,const Genesys_Sensor & sensor,Genesys_Register_Set * reg) const880 void CommandSetGl842::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor,
881                                            Genesys_Register_Set* reg) const
882 {
883     DBG_HELPER(dbg);
884     (void) sensor;
885 
886     unsigned channels = 3;
887     unsigned resolution = dev->model->get_resolution_settings(dev->settings.scan_method)
888                                      .get_nearest_resolution_x(600);
889 
890     const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
891                                                          dev->settings.scan_method);
892     unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH / 2;
893 
894     *reg = dev->reg;
895 
896     auto flags = ScanFlag::DISABLE_SHADING |
897                  ScanFlag::DISABLE_GAMMA |
898                  ScanFlag::SINGLE_LINE |
899                  ScanFlag::IGNORE_STAGGER_OFFSET |
900                  ScanFlag::IGNORE_COLOR_OFFSET;
901     if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
902         dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
903     {
904         flags |= ScanFlag::USE_XPA;
905     }
906 
907     ScanSession session;
908     session.params.xres = resolution;
909     session.params.yres = resolution;
910     session.params.startx = (num_pixels / 2) * resolution / calib_sensor.full_resolution;
911     session.params.starty = 0;
912     session.params.pixels = num_pixels;
913     session.params.lines = 1;
914     session.params.depth = dev->model->bpp_color_values.front();
915     session.params.channels = channels;
916     session.params.scan_method = dev->settings.scan_method;
917     session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
918     session.params.color_filter = dev->settings.color_filter;
919     session.params.flags = flags;
920 
921     compute_session(dev, session, calib_sensor);
922 
923     init_regs_for_scan_session(dev, calib_sensor, reg, session);
924 
925     sanei_genesys_set_motor_power(*reg, false);
926 }
927 
gl842_init_gpio(Genesys_Device * dev)928 static void gl842_init_gpio(Genesys_Device* dev)
929 {
930     DBG_HELPER(dbg);
931     apply_registers_ordered(dev->gpo.regs, { 0x6e, 0x6f }, [&](const GenesysRegisterSetting& reg)
932     {
933         dev->interface->write_register(reg.address, reg.value);
934     });
935 }
936 
asic_boot(Genesys_Device * dev,bool cold) const937 void CommandSetGl842::asic_boot(Genesys_Device* dev, bool cold) const
938 {
939     DBG_HELPER(dbg);
940 
941     if (cold) {
942         dev->interface->write_register(0x0e, 0x01);
943         dev->interface->write_register(0x0e, 0x00);
944     }
945 
946     // setup initial register values
947     gl842_init_registers(*dev);
948     dev->interface->write_registers(dev->reg);
949 
950     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
951         uint8_t data[32] = {
952             0xd0, 0x38, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00,
953             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
954             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
955             0x6a, 0x73, 0x63, 0x68, 0x69, 0x65, 0x6e, 0x00,
956         };
957 
958         dev->interface->write_buffer(0x3c, 0x010a00, data, 32);
959     }
960 
961     if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200) {
962         dev->interface->write_0x8c(0x10, 0x94);
963     }
964     if (dev->model->model_id == ModelId::CANON_LIDE_90) {
965         dev->interface->write_0x8c(0x10, 0xd4);
966     }
967 
968     // set RAM read address
969     dev->interface->write_register(REG_0x2A, 0x00);
970     dev->interface->write_register(REG_0x2B, 0x00);
971 
972     // setup gpio
973     gl842_init_gpio(dev);
974     dev->interface->sleep_ms(100);
975 }
976 
init(Genesys_Device * dev) const977 void CommandSetGl842::init(Genesys_Device* dev) const
978 {
979     DBG_INIT();
980     DBG_HELPER(dbg);
981 
982     sanei_genesys_asic_init(dev);
983 }
984 
update_hardware_sensors(Genesys_Scanner * s) const985 void CommandSetGl842::update_hardware_sensors(Genesys_Scanner* s) const
986 {
987     DBG_HELPER(dbg);
988     (void) s;
989 }
990 
update_home_sensor_gpio(Genesys_Device & dev) const991 void CommandSetGl842::update_home_sensor_gpio(Genesys_Device& dev) const
992 {
993     DBG_HELPER(dbg);
994     if (dev.model->model_id == ModelId::CANON_LIDE_90) {
995         std::uint8_t val = dev.interface->read_register(REG_0x6C);
996         val |= 0x02;
997         dev.interface->write_register(REG_0x6C, val);
998     }
999 }
1000 
1001 /**
1002  * Send shading calibration data. The buffer is considered to always hold values
1003  * for all the channels.
1004  */
send_shading_data(Genesys_Device * dev,const Genesys_Sensor & sensor,uint8_t * data,int size) const1005 void CommandSetGl842::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor,
1006                                         uint8_t* data, int size) const
1007 {
1008     DBG_HELPER(dbg);
1009 
1010     int offset = 0;
1011     unsigned length = size;
1012 
1013     if (dev->reg.get8(REG_0x01) & REG_0x01_SHDAREA) {
1014         offset = dev->session.params.startx * sensor.shading_resolution /
1015                  dev->session.params.xres;
1016 
1017         length = dev->session.output_pixels * sensor.shading_resolution /
1018                  dev->session.params.xres;
1019 
1020         offset += sensor.shading_pixel_offset;
1021 
1022         // 16 bit words, 2 words per color, 3 color channels
1023         length *= 2 * 2 * 3;
1024         offset *= 2 * 2 * 3;
1025     } else {
1026         offset += sensor.shading_pixel_offset * 2 * 2 * 3;
1027     }
1028 
1029     dev->interface->record_key_value("shading_offset", std::to_string(offset));
1030     dev->interface->record_key_value("shading_length", std::to_string(length));
1031 
1032     std::vector<uint8_t> final_data(length, 0);
1033 
1034     unsigned count = 0;
1035     if (offset < 0) {
1036         count += (-offset);
1037         length -= (-offset);
1038         offset = 0;
1039     }
1040     if (static_cast<int>(length) + offset > static_cast<int>(size)) {
1041         length = size - offset;
1042     }
1043 
1044     for (unsigned i = 0; i < length; i++) {
1045         final_data[count++] = data[offset + i];
1046         count++;
1047     }
1048 
1049     dev->interface->write_buffer(0x3c, 0, final_data.data(), count);
1050 }
1051 
needs_home_before_init_regs_for_scan(Genesys_Device * dev) const1052 bool CommandSetGl842::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const
1053 {
1054     (void) dev;
1055     return true;
1056 }
1057 
wait_for_motor_stop(Genesys_Device * dev) const1058 void CommandSetGl842::wait_for_motor_stop(Genesys_Device* dev) const
1059 {
1060     (void) dev;
1061 }
1062 
1063 } // namespace gl842
1064 } // namespace genesys
1065