From ad38bc6ecb80ddeb562841b33258dd53659b1da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Mon, 24 Aug 2020 18:44:51 +0200 Subject: New upstream version 1.0.31 --- backend/genesys/gl841.cpp | 3267 +++++++++++---------------------------------- 1 file changed, 788 insertions(+), 2479 deletions(-) (limited to 'backend/genesys/gl841.cpp') diff --git a/backend/genesys/gl841.cpp b/backend/genesys/gl841.cpp index 470f9ba..731354f 100644 --- a/backend/genesys/gl841.cpp +++ b/backend/genesys/gl841.cpp @@ -63,315 +63,11 @@ namespace gl841 { static int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor, + const MotorProfile& profile, float slope_dpi, - StepType scan_step_type, int start, int used_pixels); -/** copy sensor specific settings */ -/* *dev : device infos - *regs : registers to be set - extended : do extended set up - ccd_size_divisor: set up for half ccd resolution - all registers 08-0B, 10-1D, 52-59 are set up. They shouldn't - appear anywhere else but in register_ini - -Responsible for signals to CCD/CIS: - CCD_CK1X (CK1INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1MTGL(0x1C),CK1LOW(0x1D),CK1MAP(0x74,0x75,0x76),CK1NEG(0x7D)) - CCD_CK2X (CK2INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1LOW(0x1D),CK1NEG(0x7D)) - CCD_CK3X (MANUAL3(0x1A),CK3INV(0x1A),CK3MTGL(0x1C),CK3LOW(0x1D),CK3MAP(0x77,0x78,0x79),CK3NEG(0x7D)) - CCD_CK4X (MANUAL3(0x1A),CK4INV(0x1A),CK4MTGL(0x1C),CK4LOW(0x1D),CK4MAP(0x7A,0x7B,0x7C),CK4NEG(0x7D)) - CCD_CPX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),CPH(0x72),CPL(0x73),CPNEG(0x7D)) - CCD_RSX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),RSH(0x70),RSL(0x71),RSNEG(0x7D)) - CCD_TGX (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPR(0x10,0x11),TGSHLD(0x1D)) - CCD_TGG (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPG(0x12,0x13),TGSHLD(0x1D)) - CCD_TGB (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPB(0x14,0x15),TGSHLD(0x1D)) - LAMP_SW (EXPR(0x10,0x11),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29)) - XPA_SW (EXPG(0x12,0x13),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29)) - LAMP_B (EXPB(0x14,0x15),LAMP_PWR(0x03)) - -other registers: - CISSET(0x01),CNSET(0x18),DCKSEL(0x18),SCANMOD(0x18),EXPDMY(0x19),LINECLP(0x1A),CKAREA(0x1C),TGTIME(0x1C),LINESEL(0x1E),DUMMY(0x34) - -Responsible for signals to AFE: - VSMP (VSMP(0x58),VSMPW(0x58)) - BSMP (BSMP(0x59),BSMPW(0x59)) - -other register settings depending on this: - RHI(0x52),RLOW(0x53),GHI(0x54),GLOW(0x55),BHI(0x56),BLOW(0x57), - -*/ -static void sanei_gl841_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set * regs, - bool extended, unsigned ccd_size_divisor) -{ - DBG(DBG_proc, "%s\n", __func__); - - // that one is tricky at least - for (uint16_t addr = 0x08; addr <= 0x0b; ++addr) { - regs->set8(0x70 + addr - 0x08, sensor.custom_regs.get_value(addr)); - } - - // ignore registers in range [0x10..0x16) - for (uint16_t addr = 0x16; addr < 0x1e; ++addr) { - regs->set8(addr, sensor.custom_regs.get_value(addr)); - } - - // ignore registers in range [0x5b..0x5e] - for (uint16_t addr = 0x52; addr < 0x52 + 9; ++addr) { - regs->set8(addr, sensor.custom_regs.get_value(addr)); - } - - /* don't go any further if no extended setup */ - if (!extended) - return; - - /* todo : add more CCD types if needed */ - /* we might want to expand the Sensor struct to have these - 2 kind of settings */ - if (dev->model->sensor_id == SensorId::CCD_5345) { - if (ccd_size_divisor > 1) { - GenesysRegister* r; - /* settings for CCD used at half is max resolution */ - r = sanei_genesys_get_address (regs, 0x70); - r->value = 0x00; - r = sanei_genesys_get_address (regs, 0x71); - r->value = 0x05; - r = sanei_genesys_get_address (regs, 0x72); - r->value = 0x06; - r = sanei_genesys_get_address (regs, 0x73); - r->value = 0x08; - r = sanei_genesys_get_address (regs, 0x18); - r->value = 0x28; - r = sanei_genesys_get_address (regs, 0x58); - r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */ - } - else - { - GenesysRegister* r; - /* swap latch times */ - r = sanei_genesys_get_address (regs, 0x18); - r->value = 0x30; - regs->set8(0x52, sensor.custom_regs.get_value(0x55)); - regs->set8(0x53, sensor.custom_regs.get_value(0x56)); - regs->set8(0x54, sensor.custom_regs.get_value(0x57)); - regs->set8(0x55, sensor.custom_regs.get_value(0x52)); - regs->set8(0x56, sensor.custom_regs.get_value(0x53)); - regs->set8(0x57, sensor.custom_regs.get_value(0x54)); - r = sanei_genesys_get_address (regs, 0x58); - r->value = 0x20 | (r->value & 0x03); /* VSMP=4 */ - } - return; - } - - if (dev->model->sensor_id == SensorId::CCD_HP2300) { - /* settings for CCD used at half is max resolution */ - GenesysRegister* r; - if (ccd_size_divisor > 1) { - r = sanei_genesys_get_address (regs, 0x70); - r->value = 0x16; - r = sanei_genesys_get_address (regs, 0x71); - r->value = 0x00; - r = sanei_genesys_get_address (regs, 0x72); - r->value = 0x01; - r = sanei_genesys_get_address (regs, 0x73); - r->value = 0x03; - /* manual clock programming */ - r = sanei_genesys_get_address (regs, 0x1d); - r->value |= 0x80; - } - else - { - r = sanei_genesys_get_address (regs, 0x70); - r->value = 1; - r = sanei_genesys_get_address (regs, 0x71); - r->value = 3; - r = sanei_genesys_get_address (regs, 0x72); - r->value = 4; - r = sanei_genesys_get_address (regs, 0x73); - r->value = 6; - } - r = sanei_genesys_get_address (regs, 0x58); - r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */ - return; - } -} - -/* - * Set all registers LiDE 80 to default values - * (function called only once at the beginning) - * we are doing a special case to ease development - */ -static void -gl841_init_lide80 (Genesys_Device * dev) -{ - dev->reg.init_reg(0x01, 0x82); // 0x02 = SHDAREA and no CISSET ! - dev->reg.init_reg(0x02, 0x10); - dev->reg.init_reg(0x03, 0x50); - dev->reg.init_reg(0x04, 0x02); - dev->reg.init_reg(0x05, 0x4c); // 1200 DPI - dev->reg.init_reg(0x06, 0x38); // 0x38 scanmod=1, pwrbit, GAIN4 - dev->reg.init_reg(0x07, 0x00); - dev->reg.init_reg(0x08, 0x00); - dev->reg.init_reg(0x09, 0x11); - dev->reg.init_reg(0x0a, 0x00); - - dev->reg.init_reg(0x10, 0x40); - dev->reg.init_reg(0x11, 0x00); - dev->reg.init_reg(0x12, 0x40); - dev->reg.init_reg(0x13, 0x00); - dev->reg.init_reg(0x14, 0x40); - dev->reg.init_reg(0x15, 0x00); - dev->reg.init_reg(0x16, 0x00); - dev->reg.init_reg(0x17, 0x01); - dev->reg.init_reg(0x18, 0x00); - dev->reg.init_reg(0x19, 0x06); - dev->reg.init_reg(0x1a, 0x00); - dev->reg.init_reg(0x1b, 0x00); - dev->reg.init_reg(0x1c, 0x00); - dev->reg.init_reg(0x1d, 0x04); - dev->reg.init_reg(0x1e, 0x10); - dev->reg.init_reg(0x1f, 0x04); - dev->reg.init_reg(0x20, 0x02); - dev->reg.init_reg(0x21, 0x10); - dev->reg.init_reg(0x22, 0x20); - dev->reg.init_reg(0x23, 0x20); - dev->reg.init_reg(0x24, 0x10); - dev->reg.init_reg(0x25, 0x00); - dev->reg.init_reg(0x26, 0x00); - dev->reg.init_reg(0x27, 0x00); - - dev->reg.init_reg(0x29, 0xff); - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - dev->reg.init_reg(0x2c, sensor.optical_res>>8); - dev->reg.init_reg(0x2d, sensor.optical_res & 0xff); - dev->reg.init_reg(0x2e, 0x80); - dev->reg.init_reg(0x2f, 0x80); - dev->reg.init_reg(0x30, 0x00); - dev->reg.init_reg(0x31, 0x10); - dev->reg.init_reg(0x32, 0x15); - dev->reg.init_reg(0x33, 0x0e); - dev->reg.init_reg(0x34, 0x40); - dev->reg.init_reg(0x35, 0x00); - dev->reg.init_reg(0x36, 0x2a); - dev->reg.init_reg(0x37, 0x30); - dev->reg.init_reg(0x38, 0x2a); - dev->reg.init_reg(0x39, 0xf8); - - dev->reg.init_reg(0x3d, 0x00); - dev->reg.init_reg(0x3e, 0x00); - dev->reg.init_reg(0x3f, 0x00); - - dev->reg.init_reg(0x52, 0x03); - dev->reg.init_reg(0x53, 0x07); - dev->reg.init_reg(0x54, 0x00); - dev->reg.init_reg(0x55, 0x00); - dev->reg.init_reg(0x56, 0x00); - dev->reg.init_reg(0x57, 0x00); - dev->reg.init_reg(0x58, 0x29); - dev->reg.init_reg(0x59, 0x69); - dev->reg.init_reg(0x5a, 0x55); - - dev->reg.init_reg(0x5d, 0x20); - dev->reg.init_reg(0x5e, 0x41); - dev->reg.init_reg(0x5f, 0x40); - dev->reg.init_reg(0x60, 0x00); - dev->reg.init_reg(0x61, 0x00); - dev->reg.init_reg(0x62, 0x00); - dev->reg.init_reg(0x63, 0x00); - dev->reg.init_reg(0x64, 0x00); - dev->reg.init_reg(0x65, 0x00); - dev->reg.init_reg(0x66, 0x00); - dev->reg.init_reg(0x67, 0x40); - dev->reg.init_reg(0x68, 0x40); - dev->reg.init_reg(0x69, 0x20); - dev->reg.init_reg(0x6a, 0x20); - dev->reg.init_reg(0x6c, 0x00); - dev->reg.init_reg(0x6d, 0x00); - dev->reg.init_reg(0x6e, 0x00); - dev->reg.init_reg(0x6f, 0x00); - dev->reg.init_reg(0x70, 0x00); - dev->reg.init_reg(0x71, 0x05); - dev->reg.init_reg(0x72, 0x07); - dev->reg.init_reg(0x73, 0x09); - dev->reg.init_reg(0x74, 0x00); - dev->reg.init_reg(0x75, 0x01); - dev->reg.init_reg(0x76, 0xff); - dev->reg.init_reg(0x77, 0x00); - dev->reg.init_reg(0x78, 0x0f); - dev->reg.init_reg(0x79, 0xf0); - dev->reg.init_reg(0x7a, 0xf0); - dev->reg.init_reg(0x7b, 0x00); - dev->reg.init_reg(0x7c, 0x1e); - dev->reg.init_reg(0x7d, 0x11); - dev->reg.init_reg(0x7e, 0x00); - dev->reg.init_reg(0x7f, 0x50); - dev->reg.init_reg(0x80, 0x00); - dev->reg.init_reg(0x81, 0x00); - dev->reg.init_reg(0x82, 0x0f); - dev->reg.init_reg(0x83, 0x00); - dev->reg.init_reg(0x84, 0x0e); - dev->reg.init_reg(0x85, 0x00); - dev->reg.init_reg(0x86, 0x0d); - dev->reg.init_reg(0x87, 0x02); - dev->reg.init_reg(0x88, 0x00); - dev->reg.init_reg(0x89, 0x00); - - for (const auto& reg : dev->gpo.regs) { - dev->reg.set8(reg.address, reg.value); - } - - // specific scanner settings, clock and gpio first - // FIXME: remove the dummy reads as we don't use the values - if (!is_testing_mode()) { - dev->interface->read_register(REG_0x6B); - } - dev->interface->write_register(REG_0x6B, 0x0c); - dev->interface->write_register(0x06, 0x10); - dev->interface->write_register(REG_0x6E, 0x6d); - dev->interface->write_register(REG_0x6F, 0x80); - dev->interface->write_register(REG_0x6B, 0x0e); - if (!is_testing_mode()) { - dev->interface->read_register(REG_0x6C); - } - dev->interface->write_register(REG_0x6C, 0x00); - if (!is_testing_mode()) { - dev->interface->read_register(REG_0x6D); - } - dev->interface->write_register(REG_0x6D, 0x8f); - if (!is_testing_mode()) { - dev->interface->read_register(REG_0x6B); - } - dev->interface->write_register(REG_0x6B, 0x0e); - if (!is_testing_mode()) { - dev->interface->read_register(REG_0x6B); - } - dev->interface->write_register(REG_0x6B, 0x0e); - if (!is_testing_mode()) { - dev->interface->read_register(REG_0x6B); - } - dev->interface->write_register(REG_0x6B, 0x0a); - if (!is_testing_mode()) { - dev->interface->read_register(REG_0x6B); - } - dev->interface->write_register(REG_0x6B, 0x02); - if (!is_testing_mode()) { - dev->interface->read_register(REG_0x6B); - } - dev->interface->write_register(REG_0x6B, 0x06); - - dev->interface->write_0x8c(0x10, 0x94); - dev->interface->write_register(0x09, 0x10); - - // FIXME: the following code originally changed 0x6b, but due to bug the 0x6c register was - // effectively changed. The current behavior matches the old code, but should probably be fixed. - dev->reg.find_reg(0x6c).value |= REG_0x6B_GPO18; - dev->reg.find_reg(0x6c).value &= ~REG_0x6B_GPO17; - - sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 0, 1); -} - /* * Set all registers to default values * (function called only once at the beginning) @@ -379,139 +75,232 @@ gl841_init_lide80 (Genesys_Device * dev) static void gl841_init_registers (Genesys_Device * dev) { - int addr; - - DBG(DBG_proc, "%s\n", __func__); - - dev->reg.clear(); - if (dev->model->model_id == ModelId::CANON_LIDE_80) { - gl841_init_lide80(dev); - return ; - } - - for (addr = 1; addr <= 0x0a; addr++) { - dev->reg.init_reg(addr, 0); - } - for (addr = 0x10; addr <= 0x27; addr++) { - dev->reg.init_reg(addr, 0); - } - dev->reg.init_reg(0x29, 0); - for (addr = 0x2c; addr <= 0x39; addr++) - dev->reg.init_reg(addr, 0); - for (addr = 0x3d; addr <= 0x3f; addr++) - dev->reg.init_reg(addr, 0); - for (addr = 0x52; addr <= 0x5a; addr++) - dev->reg.init_reg(addr, 0); - for (addr = 0x5d; addr <= 0x87; addr++) - dev->reg.init_reg(addr, 0); - + DBG_HELPER(dbg); - dev->reg.find_reg(0x01).value = 0x20; /* (enable shading), CCD, color, 1M */ + dev->reg.init_reg(0x01, 0x20); if (dev->model->is_cis) { dev->reg.find_reg(0x01).value |= REG_0x01_CISSET; } else { dev->reg.find_reg(0x01).value &= ~REG_0x01_CISSET; } + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x01, 0x82); + } - dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */ - dev->reg.find_reg(0x02).value |= REG_0x02_AGOHOME; - sanei_genesys_set_motor_power(dev->reg, true); - dev->reg.find_reg(0x02).value |= REG_0x02_FASTFED; - - dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */ - dev->reg.find_reg(0x03).value |= REG_0x03_AVEENB; + dev->reg.init_reg(0x02, 0x38); + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x02, 0x10); + } - if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) { - // AD front end - dev->reg.find_reg(0x04).value = (2 << REG_0x04S_AFEMOD) | 0x02; + dev->reg.init_reg(0x03, 0x5f); + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x03, 0x50); } - else /* Wolfson front end */ - { - dev->reg.find_reg(0x04).value |= 1 << REG_0x04S_AFEMOD; + + dev->reg.init_reg(0x04, 0x10); + if (dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600) { + dev->reg.init_reg(0x04, 0x22); + } else if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x04, 0x02); } - const auto& sensor = sanei_genesys_find_sensor_any(dev); + const auto& sensor = sanei_genesys_find_sensor_any(dev); - dev->reg.find_reg(0x05).value = 0x00; /* disable gamma, 24 clocks/pixel */ + dev->reg.init_reg(0x05, 0x00); // disable gamma, 24 clocks/pixel - unsigned dpihw = 0; - if (sensor.sensor_pixels < 0x1500) { - dpihw = 600; - } else if (sensor.sensor_pixels < 0x2a80) { - dpihw = 1200; - } else if (sensor.sensor_pixels < 0x5400) { - dpihw = 2400; - } else { - throw SaneException("Cannot handle sensor pixel count %d", sensor.sensor_pixels); - } - sanei_genesys_set_dpihw(dev->reg, sensor, dpihw); + sanei_genesys_set_dpihw(dev->reg, sensor.register_dpihw); - dev->reg.find_reg(0x06).value |= REG_0x06_PWRBIT; - dev->reg.find_reg(0x06).value |= REG_0x06_GAIN4; + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x05, 0x4c); + } - /* XP300 CCD needs different clock and clock/pixels values */ - if (dev->model->sensor_id != SensorId::CCD_XP300 && - dev->model->sensor_id != SensorId::CCD_DP685 && - dev->model->sensor_id != SensorId::CCD_PLUSTEK_OPTICPRO_3600) - { - dev->reg.find_reg(0x06).value |= 0 << REG_0x06S_SCANMOD; - dev->reg.find_reg(0x09).value |= 1 << REG_0x09S_CLKSET; + dev->reg.init_reg(0x06, 0x18); + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x06, 0x38); } - else + if (dev->model->model_id == ModelId::VISIONEER_STROBE_XP300 || + dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_485 || + dev->model->model_id == ModelId::DCT_DOCKETPORT_487 || + dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_685 || + dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600) { - dev->reg.find_reg(0x06).value |= 0x05 << REG_0x06S_SCANMOD; /* 15 clocks/pixel */ - dev->reg.find_reg(0x09).value = 0; /* 24 MHz CLKSET */ + dev->reg.init_reg(0x06, 0xb8); } - dev->reg.find_reg(0x1e).value = 0xf0; /* watch-dog time */ - - dev->reg.find_reg(0x17).value |= 1 << REG_0x17S_TGW; - - dev->reg.find_reg(0x19).value = 0x50; - - dev->reg.find_reg(0x1d).value |= 1 << REG_0x1DS_TGSHLD; - - dev->reg.find_reg(0x1e).value |= 1 << REG_0x1ES_WDTIME; - -/*SCANFED*/ - dev->reg.find_reg(0x1f).value = 0x01; + dev->reg.init_reg(0x07, 0x00); + dev->reg.init_reg(0x08, 0x00); -/*BUFSEL*/ - dev->reg.find_reg(0x20).value = 0x20; + dev->reg.init_reg(0x09, 0x10); + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x09, 0x11); + } + if (dev->model->model_id == ModelId::VISIONEER_STROBE_XP300 || + dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_485 || + dev->model->model_id == ModelId::DCT_DOCKETPORT_487 || + dev->model->model_id == ModelId::SYSCAN_DOCKETPORT_685 || + dev->model->model_id == ModelId::PLUSTEK_OPTICPRO_3600) + { + dev->reg.init_reg(0x09, 0x00); + } + dev->reg.init_reg(0x0a, 0x00); -/*LAMPPWM*/ - dev->reg.find_reg(0x29).value = 0xff; + // EXPR[0:15], EXPG[0:15], EXPB[0:15]: Exposure time settings + dev->reg.init_reg(0x10, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x11, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x12, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x13, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x14, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x15, 0x00); // SENSOR_DEF + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x10, 0x40); + dev->reg.init_reg(0x11, 0x00); + dev->reg.init_reg(0x12, 0x40); + dev->reg.init_reg(0x13, 0x00); + dev->reg.init_reg(0x14, 0x40); + dev->reg.init_reg(0x15, 0x00); + } + + dev->reg.init_reg(0x16, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x17, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x18, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x19, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x1a, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x1b, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x1c, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x1d, 0x01); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x1e, 0xf0); + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x1e, 0x10); + } + dev->reg.init_reg(0x1f, 0x01); + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x1f, 0x04); + } + dev->reg.init_reg(0x20, 0x20); + dev->reg.init_reg(0x21, 0x01); + dev->reg.init_reg(0x22, 0x01); + dev->reg.init_reg(0x23, 0x01); + dev->reg.init_reg(0x24, 0x01); + dev->reg.init_reg(0x25, 0x00); + dev->reg.init_reg(0x26, 0x00); + dev->reg.init_reg(0x27, 0x00); + dev->reg.init_reg(0x29, 0xff); -/*BWHI*/ - dev->reg.find_reg(0x2e).value = 0x80; + dev->reg.init_reg(0x2c, 0x00); + dev->reg.init_reg(0x2d, 0x00); + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x2c, sensor.full_resolution >> 8); + dev->reg.init_reg(0x2d, sensor.full_resolution & 0xff); + } + dev->reg.init_reg(0x2e, 0x80); + dev->reg.init_reg(0x2f, 0x80); -/*BWLOW*/ - dev->reg.find_reg(0x2f).value = 0x80; + dev->reg.init_reg(0x30, 0x00); + dev->reg.init_reg(0x31, 0x00); + dev->reg.init_reg(0x32, 0x00); + dev->reg.init_reg(0x33, 0x00); + dev->reg.init_reg(0x34, 0x00); + dev->reg.init_reg(0x35, 0x00); + dev->reg.init_reg(0x36, 0x00); + dev->reg.init_reg(0x37, 0x00); + dev->reg.init_reg(0x38, 0x4f); + dev->reg.init_reg(0x39, 0xc1); + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x31, 0x10); + dev->reg.init_reg(0x32, 0x15); + dev->reg.init_reg(0x33, 0x0e); + dev->reg.init_reg(0x34, 0x40); + dev->reg.init_reg(0x35, 0x00); + dev->reg.init_reg(0x36, 0x2a); + dev->reg.init_reg(0x37, 0x30); + dev->reg.init_reg(0x38, 0x2a); + dev->reg.init_reg(0x39, 0xf8); + } -/*LPERIOD*/ - dev->reg.find_reg(0x38).value = 0x4f; - dev->reg.find_reg(0x39).value = 0xc1; + dev->reg.init_reg(0x3d, 0x00); + dev->reg.init_reg(0x3e, 0x00); + dev->reg.init_reg(0x3f, 0x00); -/*VSMPW*/ - dev->reg.find_reg(0x58).value |= 3 << REG_0x58S_VSMPW; + dev->reg.init_reg(0x52, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x53, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x54, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x55, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x56, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x57, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x58, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x59, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x5a, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below -/*BSMPW*/ - dev->reg.find_reg(0x59).value |= 3 << REG_0x59S_BSMPW; + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x5d, 0x20); + dev->reg.init_reg(0x5e, 0x41); + dev->reg.init_reg(0x5f, 0x40); + dev->reg.init_reg(0x60, 0x00); + dev->reg.init_reg(0x61, 0x00); + dev->reg.init_reg(0x62, 0x00); + dev->reg.init_reg(0x63, 0x00); + dev->reg.init_reg(0x64, 0x00); + dev->reg.init_reg(0x65, 0x00); + dev->reg.init_reg(0x66, 0x00); + dev->reg.init_reg(0x67, 0x40); + dev->reg.init_reg(0x68, 0x40); + dev->reg.init_reg(0x69, 0x20); + dev->reg.init_reg(0x6a, 0x20); + dev->reg.init_reg(0x6c, 0x00); + dev->reg.init_reg(0x6d, 0x00); + dev->reg.init_reg(0x6e, 0x00); + dev->reg.init_reg(0x6f, 0x00); + } else { + for (unsigned addr = 0x5d; addr <= 0x6f; addr++) { + dev->reg.init_reg(addr, 0); + } + dev->reg.init_reg(0x5e, 0x02); + if (dev->model->model_id == ModelId::CANON_LIDE_60) { + dev->reg.init_reg(0x66, 0xff); + } + } -/*RLCSEL*/ - dev->reg.find_reg(0x5a).value |= REG_0x5A_RLCSEL; + dev->reg.init_reg(0x70, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x71, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x72, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below + dev->reg.init_reg(0x73, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below -/*STOPTIM*/ - dev->reg.find_reg(0x5e).value |= 0x2 << REG_0x5ES_STOPTIM; + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + dev->reg.init_reg(0x74, 0x00); + dev->reg.init_reg(0x75, 0x01); + dev->reg.init_reg(0x76, 0xff); + dev->reg.init_reg(0x77, 0x00); + dev->reg.init_reg(0x78, 0x0f); + dev->reg.init_reg(0x79, 0xf0); + dev->reg.init_reg(0x7a, 0xf0); + dev->reg.init_reg(0x7b, 0x00); + dev->reg.init_reg(0x7c, 0x1e); + dev->reg.init_reg(0x7d, 0x11); + dev->reg.init_reg(0x7e, 0x00); + dev->reg.init_reg(0x7f, 0x50); + dev->reg.init_reg(0x80, 0x00); + dev->reg.init_reg(0x81, 0x00); + dev->reg.init_reg(0x82, 0x0f); + dev->reg.init_reg(0x83, 0x00); + dev->reg.init_reg(0x84, 0x0e); + dev->reg.init_reg(0x85, 0x00); + dev->reg.init_reg(0x86, 0x0d); + dev->reg.init_reg(0x87, 0x02); + dev->reg.init_reg(0x88, 0x00); + dev->reg.init_reg(0x89, 0x00); + } else { + for (unsigned addr = 0x74; addr <= 0x87; addr++) { + dev->reg.init_reg(addr, 0); + } + } - sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 0, 1); + scanner_setup_sensor(*dev, sensor, dev->reg); // set up GPIO for (const auto& reg : dev->gpo.regs) { dev->reg.set8(reg.address, reg.value); } - /* TODO there is a switch calling to be written here */ if (dev->model->gpio_id == GpioId::CANON_LIDE_35) { dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO18; dev->reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17; @@ -523,70 +312,43 @@ gl841_init_registers (Genesys_Device * dev) if (dev->model->gpio_id == GpioId::DP685) { /* REG_0x6B_GPO18 lights on green led */ - dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17|REG_0x6B_GPO18; - } - - DBG(DBG_proc, "%s complete\n", __func__); -} - -// Send slope table for motor movement slope_table in machine byte order -static void gl841_send_slope_table(Genesys_Device* dev, int table_nr, - const std::vector& slope_table, - int steps) -{ - DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps); - int dpihw; - int start_address; - char msg[4000]; -/*#ifdef WORDS_BIGENDIAN*/ - int i; -/*#endif*/ - - dpihw = dev->reg.find_reg(0x05).value >> 6; - - if (dpihw == 0) /* 600 dpi */ - start_address = 0x08000; - else if (dpihw == 1) /* 1200 dpi */ - start_address = 0x10000; - else if (dpihw == 2) /* 2400 dpi */ - start_address = 0x20000; - else { - throw SaneException("Unexpected dpihw"); - } - - std::vector table(steps * 2); - for(i = 0; i < steps; i++) { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } - - if (DBG_LEVEL >= DBG_io) - { - std::sprintf(msg, "write slope %d (%d)=", table_nr, steps); - for (i = 0; i < steps; i++) { - std::sprintf (msg+strlen(msg), ",%d", slope_table[i]); - } - DBG(DBG_io, "%s: %s\n", __func__, msg); + dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17 | REG_0x6B_GPO18; } - if (dev->interface->is_mock()) { - dev->interface->record_slope_table(table_nr, slope_table); + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + // specific scanner settings, clock and gpio first + dev->interface->write_register(REG_0x6B, 0x0c); + dev->interface->write_register(0x06, 0x10); + dev->interface->write_register(REG_0x6E, 0x6d); + dev->interface->write_register(REG_0x6F, 0x80); + dev->interface->write_register(REG_0x6B, 0x0e); + dev->interface->write_register(REG_0x6C, 0x00); + dev->interface->write_register(REG_0x6D, 0x8f); + dev->interface->write_register(REG_0x6B, 0x0e); + dev->interface->write_register(REG_0x6B, 0x0e); + dev->interface->write_register(REG_0x6B, 0x0a); + dev->interface->write_register(REG_0x6B, 0x02); + dev->interface->write_register(REG_0x6B, 0x06); + + dev->interface->write_0x8c(0x10, 0x94); + dev->interface->write_register(0x09, 0x10); + + // FIXME: the following code originally changed 0x6b, but due to bug the 0x6c register was + // effectively changed. The current behavior matches the old code, but should probably be fixed. + dev->reg.find_reg(0x6c).value |= REG_0x6B_GPO18; + dev->reg.find_reg(0x6c).value &= ~REG_0x6B_GPO17; } - dev->interface->write_buffer(0x3c, start_address + table_nr * 0x200, table.data(), steps * 2); } static void gl841_set_lide80_fe(Genesys_Device* dev, uint8_t set) { DBG_HELPER(dbg); - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, - static_cast(dev->model->adc_id)); - - dev->frontend = dev->frontend_initial; + if (set == AFE_INIT) { + dev->frontend = dev->frontend_initial; - // write them to analog frontend + // BUG: the following code does not make sense. The addresses are different than AFE_SET + // case dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x01)); dev->interface->write_fe_register(0x06, dev->frontend.regs.get_value(0x02)); @@ -611,11 +373,7 @@ static void gl841_set_ad_fe(Genesys_Device* dev, uint8_t set) return; } - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, - static_cast(dev->model->adc_id)); - + if (set == AFE_INIT) { dev->frontend = dev->frontend_initial; // write them to analog frontend @@ -674,15 +432,11 @@ void CommandSetGl841::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, throw SaneException("unsupported frontend type %d", frontend_type); } - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, - static_cast(dev->model->adc_id)); - dev->frontend = dev->frontend_initial; + if (set == AFE_INIT) { + dev->frontend = dev->frontend_initial; // reset only done on init dev->interface->write_fe_register(0x04, 0x80); - DBG(DBG_proc, "%s(): frontend reset complete\n", __func__); } @@ -712,71 +466,34 @@ void CommandSetGl841::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, } } -enum MotorAction { - MOTOR_ACTION_FEED = 1, - MOTOR_ACTION_GO_HOME = 2, - MOTOR_ACTION_HOME_FREE = 3 -}; - // @brief turn off motor static void gl841_init_motor_regs_off(Genesys_Register_Set* reg, unsigned int scan_lines) { DBG_HELPER_ARGS(dbg, "scan_lines=%d", scan_lines); unsigned int feedl; - GenesysRegister* r; feedl = 2; - r = sanei_genesys_get_address (reg, 0x3d); - r->value = (feedl >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x3e); - r->value = (feedl >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x3f); - r->value = feedl & 0xff; - r = sanei_genesys_get_address (reg, 0x5e); - r->value &= ~0xe0; - - r = sanei_genesys_get_address (reg, 0x25); - r->value = (scan_lines >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x26); - r->value = (scan_lines >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x27); - r->value = scan_lines & 0xff; - - r = sanei_genesys_get_address (reg, 0x02); - r->value &= ~0x01; /*LONGCURV OFF*/ - r->value &= ~0x80; /*NOT_HOME OFF*/ - - r->value &= ~0x10; - - r->value &= ~0x06; - - r->value &= ~0x08; - - r->value &= ~0x20; - - r->value &= ~0x40; + reg->set8(0x3d, (feedl >> 16) & 0xf); + reg->set8(0x3e, (feedl >> 8) & 0xff); + reg->set8(0x3f, feedl & 0xff); + reg->find_reg(0x5e).value &= ~0xe0; - r = sanei_genesys_get_address (reg, 0x67); - r->value = 0x3f; + reg->set8(0x25, (scan_lines >> 16) & 0xf); + reg->set8(0x26, (scan_lines >> 8) & 0xff); + reg->set8(0x27, scan_lines & 0xff); - r = sanei_genesys_get_address (reg, 0x68); - r->value = 0x3f; + reg->set8(0x02, 0x00); - r = sanei_genesys_get_address(reg, REG_STEPNO); - r->value = 0; + reg->set8(0x67, 0x3f); + reg->set8(0x68, 0x3f); - r = sanei_genesys_get_address(reg, REG_FASTNO); - r->value = 0; + reg->set8(REG_STEPNO, 1); + reg->set8(REG_FASTNO, 1); - r = sanei_genesys_get_address (reg, 0x69); - r->value = 0; - - r = sanei_genesys_get_address (reg, 0x6a); - r->value = 0; - - r = sanei_genesys_get_address (reg, 0x5f); - r->value = 0; + reg->set8(0x69, 1); + reg->set8(0x6a, 1); + reg->set8(0x5f, 1); } /** @brief write motor table frequency @@ -814,207 +531,122 @@ uint8_t *table; table=tdefault; } dev->interface->write_register(0x66, 0x00); - dev->interface->write_gamma(0x28, 0xc000, table, 128, - ScannerInterface::FLAG_SWAP_REGISTERS); + dev->interface->write_gamma(0x28, 0xc000, table, 128); dev->interface->write_register(0x5b, 0x00); dev->interface->write_register(0x5c, 0x00); } } - -static void gl841_init_motor_regs(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set* reg, unsigned int feed_steps,/*1/base_ydpi*/ - /*maybe float for half/quarter step resolution?*/ - unsigned int action, MotorFlag flags) +static void gl841_init_motor_regs_feed(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, unsigned int feed_steps,/*1/base_ydpi*/ + ScanFlag flags) { - DBG_HELPER_ARGS(dbg, "feed_steps=%d, action=%d, flags=%x", feed_steps, action, - static_cast(flags)); - unsigned int fast_exposure = 0; + DBG_HELPER_ARGS(dbg, "feed_steps=%d, flags=%x", feed_steps, static_cast(flags)); + unsigned step_multiplier = 2; int use_fast_fed = 0; unsigned int feedl; - GenesysRegister* r; /*number of scan lines to add in a scan_lines line*/ { std::vector table; table.resize(256, 0xffff); - gl841_send_slope_table(dev, 0, table, 256); - gl841_send_slope_table(dev, 1, table, 256); - gl841_send_slope_table(dev, 2, table, 256); - gl841_send_slope_table(dev, 3, table, 256); - gl841_send_slope_table(dev, 4, table, 256); + scanner_send_slope_table(dev, sensor, 0, table); + scanner_send_slope_table(dev, sensor, 1, table); + scanner_send_slope_table(dev, sensor, 2, table); + scanner_send_slope_table(dev, sensor, 3, table); + scanner_send_slope_table(dev, sensor, 4, table); } gl841_write_freq(dev, dev->motor.base_ydpi / 4); - if (action == MOTOR_ACTION_FEED || action == MOTOR_ACTION_GO_HOME) { - /* FEED and GO_HOME can use fastest slopes available */ - fast_exposure = gl841_exposure_time(dev, sensor, - dev->motor.base_ydpi / 4, - StepType::FULL, - 0, - 0); - DBG(DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); - } + // FIXME: use proper scan session + ScanSession session; + session.params.yres = dev->motor.base_ydpi; + session.params.scan_method = dev->model->default_method; - if (action == MOTOR_ACTION_HOME_FREE) { -/* HOME_FREE must be able to stop in one step, so do not try to get faster */ - fast_exposure = dev->motor.get_slope(StepType::FULL).max_speed_w; + const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session); + if (fast_profile == nullptr) { + fast_profile = get_motor_profile_ptr(dev->motor.profiles, 0, session); } + auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier, + *fast_profile); - auto fast_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor, - StepType::FULL, fast_exposure, - dev->motor.base_ydpi / 4); - - feedl = feed_steps - fast_table.steps_count * 2; + // BUG: fast table is counted in base_ydpi / 4 + feedl = feed_steps - fast_table.table.size() * 2; use_fast_fed = 1; + if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) { + use_fast_fed = false; + } -/* all needed slopes available. we did even decide which mode to use. - what next? - - transfer slopes -SCAN: -flags \ use_fast_fed ! 0 1 -------------------------\-------------------- - 0 ! 0,1,2 0,1,2,3 -MotorFlag::AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4 -OFF: none -FEED: 3 -GO_HOME: 3 -HOME_FREE: 3 - - setup registers - * slope specific registers (already done) - * DECSEL for HOME_FREE/GO_HOME/SCAN - * FEEDL - * MTRREV - * MTRPWR - * FASTFED - * STEPSEL - * MTRPWM - * FSTPSEL - * FASTPWM - * HOMENEG - * BWDSTEP - * FWDSTEP - * Z1 - * Z2 - */ + reg->set8(0x3d, (feedl >> 16) & 0xf); + reg->set8(0x3e, (feedl >> 8) & 0xff); + reg->set8(0x3f, feedl & 0xff); + reg->find_reg(0x5e).value &= ~0xe0; - r = sanei_genesys_get_address(reg, 0x3d); - r->value = (feedl >> 16) & 0xf; - r = sanei_genesys_get_address(reg, 0x3e); - r->value = (feedl >> 8) & 0xff; - r = sanei_genesys_get_address(reg, 0x3f); - r->value = feedl & 0xff; - r = sanei_genesys_get_address(reg, 0x5e); - r->value &= ~0xe0; - - r = sanei_genesys_get_address(reg, 0x25); - r->value = 0; - r = sanei_genesys_get_address(reg, 0x26); - r->value = 0; - r = sanei_genesys_get_address(reg, 0x27); - r->value = 0; - - r = sanei_genesys_get_address(reg, 0x02); - r->value &= ~0x01; /*LONGCURV OFF*/ - r->value &= ~0x80; /*NOT_HOME OFF*/ - - r->value |= 0x10; - - if (action == MOTOR_ACTION_GO_HOME) - r->value |= 0x06; - else - r->value &= ~0x06; + reg->set8(0x25, 0); + reg->set8(0x26, 0); + reg->set8(0x27, 0); + + reg->find_reg(0x02).value &= ~0x01; /*LONGCURV OFF*/ + reg->find_reg(0x02).value &= ~0x80; /*NOT_HOME OFF*/ + + reg->find_reg(0x02).value |= REG_0x02_MTRPWR; if (use_fast_fed) - r->value |= 0x08; + reg->find_reg(0x02).value |= 0x08; else - r->value &= ~0x08; + reg->find_reg(0x02).value &= ~0x08; - if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) { - r->value |= 0x20; + if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) { + reg->find_reg(0x02).value |= 0x20; } else { - r->value &= ~0x20; + reg->find_reg(0x02).value &= ~0x20; } - r->value &= ~0x40; + reg->find_reg(0x02).value &= ~0x40; - if (has_flag(flags, MotorFlag::REVERSE)) { - r->value |= REG_0x02_MTRREV; + if (has_flag(flags, ScanFlag::REVERSE)) { + reg->find_reg(0x02).value |= REG_0x02_MTRREV; + } else { + reg->find_reg(0x02).value &= ~REG_0x02_MTRREV; } - gl841_send_slope_table(dev, 3, fast_table.table, 256); - - r = sanei_genesys_get_address(reg, 0x67); - r->value = 0x3f; - - r = sanei_genesys_get_address(reg, 0x68); - r->value = 0x3f; - - r = sanei_genesys_get_address(reg, REG_STEPNO); - r->value = 0; - - r = sanei_genesys_get_address(reg, REG_FASTNO); - r->value = 0; + scanner_send_slope_table(dev, sensor, 3, fast_table.table); - r = sanei_genesys_get_address(reg, 0x69); - r->value = 0; - - r = sanei_genesys_get_address(reg, 0x6a); - r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1); - - r = sanei_genesys_get_address(reg, 0x5f); - r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1); + reg->set8(0x67, 0x3f); + reg->set8(0x68, 0x3f); + reg->set8(REG_STEPNO, 1); + reg->set8(REG_FASTNO, 1); + reg->set8(0x69, 1); + reg->set8(0x6a, fast_table.table.size() / step_multiplier); + reg->set8(0x5f, 1); } static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set* reg, + const ScanSession& session, + Genesys_Register_Set* reg, const MotorProfile& motor_profile, unsigned int scan_exposure_time,/*pixel*/ unsigned scan_yres, // dpi, motor resolution - StepType scan_step_type, unsigned int scan_lines,/*lines, scan resolution*/ unsigned int scan_dummy, // number of scan lines to add in a scan_lines line unsigned int feed_steps,/*1/base_ydpi*/ // maybe float for half/quarter step resolution? - MotorFlag flags) + ScanFlag flags) { DBG_HELPER_ARGS(dbg, "scan_exposure_time=%d, scan_yres=%d, scan_step_type=%d, scan_lines=%d," " scan_dummy=%d, feed_steps=%d, flags=%x", - scan_exposure_time, scan_yres, static_cast(scan_step_type), + scan_exposure_time, scan_yres, static_cast(motor_profile.step_type), scan_lines, scan_dummy, feed_steps, static_cast(flags)); - unsigned int fast_exposure; + + unsigned step_multiplier = 2; + int use_fast_fed = 0; unsigned int fast_time; unsigned int slow_time; unsigned int feedl; - GenesysRegister* r; unsigned int min_restep = 0x20; - uint32_t z1, z2; - - fast_exposure = gl841_exposure_time(dev, sensor, - dev->motor.base_ydpi / 4, - StepType::FULL, - 0, - 0); - - DBG(DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); - - { - std::vector table; - table.resize(256, 0xffff); - - gl841_send_slope_table(dev, 0, table, 256); - gl841_send_slope_table(dev, 1, table, 256); - gl841_send_slope_table(dev, 2, table, 256); - gl841_send_slope_table(dev, 3, table, 256); - gl841_send_slope_table(dev, 4, table, 256); - } - - - /* motor frequency table */ - gl841_write_freq(dev, scan_yres); /* we calculate both tables for SCAN. the fast slope step count depends on @@ -1022,30 +654,31 @@ static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor allowed to use. */ - auto slow_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor, - scan_step_type, scan_exposure_time, - scan_yres); + // At least in LiDE 50, 60 the fast movement table is counted in full steps. + const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session); + if (fast_profile == nullptr) { + fast_profile = &motor_profile; + } - auto back_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor, - scan_step_type, 0, scan_yres); + auto slow_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres, + scan_exposure_time, step_multiplier, motor_profile); - if (feed_steps < (slow_table.steps_count >> static_cast(scan_step_type))) { + if (feed_steps < (slow_table.table.size() >> static_cast(motor_profile.step_type))) { /*TODO: what should we do here?? go back to exposure calculation?*/ - feed_steps = slow_table.steps_count >> static_cast(scan_step_type); + feed_steps = slow_table.table.size() >> static_cast(motor_profile.step_type); } - auto fast_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor, - StepType::FULL, fast_exposure, - dev->motor.base_ydpi / 4); + auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier, + *fast_profile); - unsigned max_fast_slope_steps_count = 1; - if (feed_steps > (slow_table.steps_count >> static_cast(scan_step_type)) + 2) { + unsigned max_fast_slope_steps_count = step_multiplier; + if (feed_steps > (slow_table.table.size() >> static_cast(motor_profile.step_type)) + 2) { max_fast_slope_steps_count = (feed_steps - - (slow_table.steps_count >> static_cast(scan_step_type))) / 2; + (slow_table.table.size() >> static_cast(motor_profile.step_type))) / 2; } - if (fast_table.steps_count > max_fast_slope_steps_count) { - fast_table.slice_steps(max_fast_slope_steps_count); + if (fast_table.table.size() > max_fast_slope_steps_count) { + fast_table.slice_steps(max_fast_slope_steps_count, step_multiplier); } /* fast fed special cases handling */ @@ -1056,8 +689,8 @@ static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor 2-feed mode */ use_fast_fed = 0; } - else if (feed_steps < fast_table.steps_count * 2 + - (slow_table.steps_count >> static_cast(scan_step_type))) + else if (feed_steps < fast_table.table.size() * 2 + + (slow_table.table.size() >> static_cast(motor_profile.step_type))) { use_fast_fed = 0; DBG(DBG_info, "%s: feed too short, slow move forced.\n", __func__); @@ -1071,113 +704,70 @@ static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor /*NOTE: fast_exposure is per base_ydpi/4*/ /*we use full steps as base unit here*/ fast_time = - fast_exposure / 4 * - (feed_steps - fast_table.steps_count*2 - - (slow_table.steps_count >> static_cast(scan_step_type))) - + fast_table.pixeltime_sum*2 + slow_table.pixeltime_sum; + (fast_table.table.back() << static_cast(fast_profile->step_type)) / 4 * + (feed_steps - fast_table.table.size()*2 - + (slow_table.table.size() >> static_cast(motor_profile.step_type))) + + fast_table.pixeltime_sum() * 2 + slow_table.pixeltime_sum(); slow_time = (scan_exposure_time * scan_yres) / dev->motor.base_ydpi * - (feed_steps - (slow_table.steps_count >> static_cast(scan_step_type))) - + slow_table.pixeltime_sum; + (feed_steps - (slow_table.table.size() >> static_cast(motor_profile.step_type))) + + slow_table.pixeltime_sum(); - DBG(DBG_info, "%s: Time for slow move: %d\n", __func__, slow_time); - DBG(DBG_info, "%s: Time for fast move: %d\n", __func__, fast_time); + use_fast_fed = fast_time < slow_time; + } - use_fast_fed = fast_time < slow_time; + if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) { + use_fast_fed = false; } if (use_fast_fed) { - feedl = feed_steps - fast_table.steps_count * 2 - - (slow_table.steps_count >> static_cast(scan_step_type)); - } else if ((feed_steps << static_cast(scan_step_type)) < slow_table.steps_count) { + feedl = feed_steps - fast_table.table.size() * 2 - + (slow_table.table.size() >> static_cast(motor_profile.step_type)); + } else if ((feed_steps << static_cast(motor_profile.step_type)) < slow_table.table.size()) { feedl = 0; } else { - feedl = (feed_steps << static_cast(scan_step_type)) - slow_table.steps_count; + feedl = (feed_steps << static_cast(motor_profile.step_type)) - slow_table.table.size(); } DBG(DBG_info, "%s: Decided to use %s mode\n", __func__, use_fast_fed?"fast feed":"slow feed"); -/* all needed slopes available. we did even decide which mode to use. - what next? - - transfer slopes -SCAN: -flags \ use_fast_fed ! 0 1 -------------------------\-------------------- - 0 ! 0,1,2 0,1,2,3 -MotorFlag::AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4 -OFF: none -FEED: 3 -GO_HOME: 3 -HOME_FREE: 3 - - setup registers - * slope specific registers (already done) - * DECSEL for HOME_FREE/GO_HOME/SCAN - * FEEDL - * MTRREV - * MTRPWR - * FASTFED - * STEPSEL - * MTRPWM - * FSTPSEL - * FASTPWM - * HOMENEG - * BWDSTEP - * FWDSTEP - * Z1 - * Z2 - */ - - r = sanei_genesys_get_address (reg, 0x3d); - r->value = (feedl >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x3e); - r->value = (feedl >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x3f); - r->value = feedl & 0xff; - r = sanei_genesys_get_address (reg, 0x5e); - r->value &= ~0xe0; - - r = sanei_genesys_get_address (reg, 0x25); - r->value = (scan_lines >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x26); - r->value = (scan_lines >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x27); - r->value = scan_lines & 0xff; - - r = sanei_genesys_get_address (reg, 0x02); - r->value &= ~0x01; /*LONGCURV OFF*/ - r->value &= ~0x80; /*NOT_HOME OFF*/ - r->value |= 0x10; - - r->value &= ~0x06; + reg->set8(0x3d, (feedl >> 16) & 0xf); + reg->set8(0x3e, (feedl >> 8) & 0xff); + reg->set8(0x3f, feedl & 0xff); + reg->find_reg(0x5e).value &= ~0xe0; + reg->set8(0x25, (scan_lines >> 16) & 0xf); + reg->set8(0x26, (scan_lines >> 8) & 0xff); + reg->set8(0x27, scan_lines & 0xff); + reg->find_reg(0x02).value = REG_0x02_MTRPWR; + + if (has_flag(flags, ScanFlag::REVERSE)) { + reg->find_reg(0x02).value |= REG_0x02_MTRREV; + } else { + reg->find_reg(0x02).value &= ~REG_0x02_MTRREV; + } if (use_fast_fed) - r->value |= 0x08; + reg->find_reg(0x02).value |= 0x08; else - r->value &= ~0x08; + reg->find_reg(0x02).value &= ~0x08; - if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) - r->value |= 0x20; + if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) + reg->find_reg(0x02).value |= 0x20; else - r->value &= ~0x20; + reg->find_reg(0x02).value &= ~0x20; - if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE)) { - r->value |= 0x40; + if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) { + reg->find_reg(0x02).value |= 0x40; } else { - r->value &= ~0x40; + reg->find_reg(0x02).value &= ~0x40; } - gl841_send_slope_table(dev, 0, slow_table.table, 256); - - gl841_send_slope_table(dev, 1, back_table.table, 256); - - gl841_send_slope_table(dev, 2, slow_table.table, 256); - - if (use_fast_fed) { - gl841_send_slope_table(dev, 3, fast_table.table, 256); - } + scanner_send_slope_table(dev, sensor, 0, slow_table.table); + scanner_send_slope_table(dev, sensor, 1, slow_table.table); + scanner_send_slope_table(dev, sensor, 2, slow_table.table); + scanner_send_slope_table(dev, sensor, 3, fast_table.table); + scanner_send_slope_table(dev, sensor, 4, fast_table.table); - if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) { - gl841_send_slope_table(dev, 4, fast_table.table, 256); - } + gl841_write_freq(dev, scan_yres); /* now reg 0x21 and 0x24 are available, we can calculate reg 0x22 and 0x23, reg 0x60-0x62 and reg 0x63-0x65 @@ -1185,19 +775,18 @@ HOME_FREE: 3 2*STEPNO+FWDSTEP=2*FASTNO+BWDSTEP */ /* steps of table 0*/ - if (min_restep < slow_table.steps_count * 2 + 2) { - min_restep = slow_table.steps_count * 2 + 2; + if (min_restep < slow_table.table.size() * 2 + 2) { + min_restep = slow_table.table.size() * 2 + 2; } /* steps of table 1*/ - if (min_restep < back_table.steps_count * 2 + 2) { - min_restep = back_table.steps_count * 2 + 2; + if (min_restep < slow_table.table.size() * 2 + 2) { + min_restep = slow_table.table.size() * 2 + 2; } /* steps of table 0*/ - r = sanei_genesys_get_address(reg, REG_FWDSTEP); - r->value = min_restep - slow_table.steps_count*2; + reg->set8(REG_FWDSTEP, min_restep - slow_table.table.size()*2); + /* steps of table 1*/ - r = sanei_genesys_get_address(reg, REG_BWDSTEP); - r->value = min_restep - back_table.steps_count*2; + reg->set8(REG_BWDSTEP, min_restep - slow_table.table.size()*2); /* for z1/z2: @@ -1214,64 +803,17 @@ HOME_FREE: 3 z1 = (slope_0_time-1) % exposure_time; z2 = (slope_0_time-1) % exposure_time; */ - z1 = z2 = 0; - - DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); - DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); - r = sanei_genesys_get_address (reg, 0x60); - r->value = ((z1 >> 16) & 0xff); - r = sanei_genesys_get_address (reg, 0x61); - r->value = ((z1 >> 8) & 0xff); - r = sanei_genesys_get_address (reg, 0x62); - r->value = (z1 & 0xff); - r = sanei_genesys_get_address (reg, 0x63); - r->value = ((z2 >> 16) & 0xff); - r = sanei_genesys_get_address (reg, 0x64); - r->value = ((z2 >> 8) & 0xff); - r = sanei_genesys_get_address (reg, 0x65); - r->value = (z2 & 0xff); - - r = sanei_genesys_get_address(reg, REG_0x1E); - r->value &= REG_0x1E_WDTIME; - r->value |= scan_dummy; - - r = sanei_genesys_get_address (reg, 0x67); - r->value = 0x3f | (static_cast(scan_step_type) << 6); - - r = sanei_genesys_get_address (reg, 0x68); - r->value = 0x3f; - - r = sanei_genesys_get_address(reg, REG_STEPNO); - r->value = (slow_table.steps_count >> 1) + (slow_table.steps_count & 1); - - r = sanei_genesys_get_address(reg, REG_FASTNO); - r->value = (back_table.steps_count >> 1) + (back_table.steps_count & 1); - - r = sanei_genesys_get_address (reg, 0x69); - r->value = (slow_table.steps_count >> 1) + (slow_table.steps_count & 1); - - r = sanei_genesys_get_address (reg, 0x6a); - r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1); - - r = sanei_genesys_get_address (reg, 0x5f); - r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1); -} - -static int -gl841_get_dpihw(Genesys_Device * dev) -{ - GenesysRegister* r; - r = sanei_genesys_get_address(&dev->reg, 0x05); - if ((r->value & REG_0x05_DPIHW) == REG_0x05_DPIHW_600) { - return 600; - } - if ((r->value & REG_0x05_DPIHW) == REG_0x05_DPIHW_1200) { - return 1200; - } - if ((r->value & REG_0x05_DPIHW) == REG_0x05_DPIHW_2400) { - return 2400; - } - return 0; + reg->set24(REG_0x60, 0); + reg->set24(REG_0x63, 0); + reg->find_reg(REG_0x1E).value &= REG_0x1E_WDTIME; + reg->find_reg(REG_0x1E).value |= scan_dummy; + reg->set8(0x67, 0x3f | (static_cast(motor_profile.step_type) << 6)); + reg->set8(0x68, 0x3f | (static_cast(fast_profile->step_type) << 6)); + reg->set8(REG_STEPNO, slow_table.table.size() / step_multiplier); + reg->set8(REG_FASTNO, slow_table.table.size() / step_multiplier); + reg->set8(0x69, slow_table.table.size() / step_multiplier); + reg->set8(0x6a, fast_table.table.size() / step_multiplier); + reg->set8(0x5f, fast_table.table.size() / step_multiplier); } static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, @@ -1279,108 +821,99 @@ static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens const ScanSession& session) { DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time); - GenesysRegister* r; uint16_t expavg, expr, expb, expg; dev->cmd_set->set_fe(dev, sensor, AFE_SET); /* gpio part.*/ if (dev->model->gpio_id == GpioId::CANON_LIDE_35) { - r = sanei_genesys_get_address(reg, REG_0x6C); - if (session.ccd_size_divisor > 1) { - r->value &= ~0x80; + if (session.params.xres <= 600) { + reg->find_reg(REG_0x6C).value &= ~0x80; } else { - r->value |= 0x80; + reg->find_reg(REG_0x6C).value |= 0x80; } } if (dev->model->gpio_id == GpioId::CANON_LIDE_80) { - r = sanei_genesys_get_address(reg, REG_0x6C); - if (session.ccd_size_divisor > 1) { - r->value &= ~0x40; - r->value |= 0x20; + if (session.params.xres <= 600) { + reg->find_reg(REG_0x6C).value &= ~0x40; + reg->find_reg(REG_0x6C).value |= 0x20; } else { - r->value &= ~0x20; - r->value |= 0x40; + reg->find_reg(REG_0x6C).value &= ~0x20; + reg->find_reg(REG_0x6C).value |= 0x40; } - } + } /* enable shading */ - r = sanei_genesys_get_address (reg, 0x01); - r->value |= REG_0x01_SCAN; + reg->find_reg(0x01).value |= REG_0x01_SCAN; if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) || - (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) { - r->value &= ~REG_0x01_DVDSET; + has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION)) { + reg->find_reg(0x01).value &= ~REG_0x01_DVDSET; } else { - r->value |= REG_0x01_DVDSET; + reg->find_reg(0x01).value |= REG_0x01_DVDSET; } /* average looks better than deletion, and we are already set up to use one of the average enabled resolutions */ - r = sanei_genesys_get_address (reg, 0x03); - r->value |= REG_0x03_AVEENB; + reg->find_reg(0x03).value |= REG_0x03_AVEENB; sanei_genesys_set_lamp_power(dev, sensor, *reg, !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP)); /* BW threshold */ - r = sanei_genesys_get_address (reg, 0x2e); - r->value = dev->settings.threshold; - r = sanei_genesys_get_address (reg, 0x2f); - r->value = dev->settings.threshold; + reg->set8(0x2e, 0x7f); + reg->set8(0x2f, 0x7f); /* monochrome / color scan */ - r = sanei_genesys_get_address (reg, 0x04); switch (session.params.depth) { case 8: - r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET); + reg->find_reg(0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET); break; case 16: - r->value &= ~REG_0x04_LINEART; - r->value |= REG_0x04_BITSET; + reg->find_reg(0x04).value &= ~REG_0x04_LINEART; + reg->find_reg(0x04).value |= REG_0x04_BITSET; break; } /* AFEMOD should depend on FESET, and we should set these * bits separately */ - r->value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD); + reg->find_reg(0x04).value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD); if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) { - r->value |= 0x10; /* no filter */ + reg->find_reg(0x04).value |= 0x10; /* no filter */ } else if (session.params.channels == 1) { switch (session.params.color_filter) { case ColorFilter::RED: - r->value |= 0x14; + reg->find_reg(0x04).value |= 0x14; break; case ColorFilter::GREEN: - r->value |= 0x18; + reg->find_reg(0x04).value |= 0x18; break; case ColorFilter::BLUE: - r->value |= 0x1c; + reg->find_reg(0x04).value |= 0x1c; break; default: - r->value |= 0x10; + reg->find_reg(0x04).value |= 0x10; break; } } else { if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) { - r->value |= 0x22; /* slow color pixel by pixel */ + reg->find_reg(0x04).value |= 0x22; /* slow color pixel by pixel */ } else { - r->value |= 0x10; /* color pixel by pixel */ + reg->find_reg(0x04).value |= 0x10; /* color pixel by pixel */ } } /* CIS scanners can do true gray by setting LEDADD */ - r = sanei_genesys_get_address (reg, 0x87); - r->value &= ~REG_0x87_LEDADD; + reg->find_reg(0x87).value &= ~REG_0x87_LEDADD; if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) { - r->value |= REG_0x87_LEDADD; + reg->find_reg(0x87).value |= REG_0x87_LEDADD; expr = reg->get16(REG_EXPR); expg = reg->get16(REG_EXPG); expb = reg->get16(REG_EXPB); @@ -1405,21 +938,14 @@ static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens } /* sensor parameters */ - sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 1, session.ccd_size_divisor); - - r = sanei_genesys_get_address (reg, 0x29); - r->value = 255; /*<<<"magic" number, only suitable for cis*/ - - reg->set16(REG_DPISET, gl841_get_dpihw(dev) * session.output_resolution / session.optical_resolution); + scanner_setup_sensor(*dev, sensor, dev->reg); + reg->set8(0x29, 255); /*<<<"magic" number, only suitable for cis*/ + reg->set16(REG_DPISET, sensor.register_dpiset); reg->set16(REG_STRPIXEL, session.pixel_startx); reg->set16(REG_ENDPIXEL, session.pixel_endx); - reg->set24(REG_MAXWD, session.output_line_bytes); - reg->set16(REG_LPERIOD, exposure_time); - - r = sanei_genesys_get_address (reg, 0x34); - r->value = sensor.dummy_pixel; + reg->set8(0x34, sensor.dummy_pixel); } static int @@ -1446,56 +972,17 @@ gl841_get_led_exposure(Genesys_Device * dev, const Genesys_Sensor& sensor) /** @brief compute exposure time * Compute exposure time for the device and the given scan resolution */ -static int -gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor, - float slope_dpi, - StepType scan_step_type, - int start, - int used_pixels) +static int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor, + const MotorProfile& profile, float slope_dpi, + int start, + int used_pixels) { -int exposure_time = 0; int led_exposure; led_exposure=gl841_get_led_exposure(dev, sensor); - exposure_time = sanei_genesys_exposure_time2( - dev, - slope_dpi, - scan_step_type, - start+used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/ - led_exposure); - - return exposure_time; -} - -/**@brief compute scan_step_type - * Try to do at least 4 steps per line. if that is impossible we will have to - * live with that. - * @param dev device - * @param yres motor resolution - */ -static StepType gl841_scan_step_type(Genesys_Device *dev, int yres) -{ - StepType type = StepType::FULL; - - /* TODO : check if there is a bug around the use of max_step_type */ - /* should be <=1, need to chek all devices entry in genesys_devices */ - if (yres * 4 < dev->motor.base_ydpi || dev->motor.max_step_type() == StepType::FULL) { - type = StepType::FULL; - } else if (yres * 4 < dev->motor.base_ydpi * 2 || - dev->motor.max_step_type() <= StepType::HALF) - { - type = StepType::HALF; - } else { - type = StepType::QUARTER; - } - - /* this motor behaves differently */ - if (dev->model->motor_id==MotorId::CANON_LIDE_80) { - // driven by 'frequency' tables ? - type = StepType::FULL; - } - - return type; + return sanei_genesys_exposure_time2(dev, profile, slope_dpi, + start + used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/ + led_exposure); } void CommandSetGl841::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, @@ -1511,34 +998,6 @@ void CommandSetGl841::init_regs_for_scan_session(Genesys_Device* dev, const Gene int slope_dpi = 0; int dummy = 0; -/* -results: - -for scanner: -start -end -dpiset -exposure_time -dummy -z1 -z2 - -for ordered_read: - dev->words_per_line - dev->read_factor - dev->requested_buffer_size - dev->read_buffer_size - dev->read_pos - dev->read_bytes_in_buffer - dev->read_bytes_left - dev->max_shift - dev->stagger - -independent of our calculated values: - dev->total_bytes_read - dev->bytes_to_read - */ - /* dummy */ /* dummy lines: may not be usefull, for instance 250 dpi works with 0 or 1 dummy line. Maybe the dummy line adds correctness since the motor runs @@ -1577,48 +1036,34 @@ dummy \ scanned lines slope_dpi = slope_dpi * (1 + dummy); - StepType scan_step_type = gl841_scan_step_type(dev, session.params.yres); - exposure_time = gl841_exposure_time(dev, sensor, - slope_dpi, - scan_step_type, - session.pixel_startx, - session.optical_pixels); - DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + const auto& motor_profile = get_motor_profile(dev->motor.profiles, 0, session); + + exposure_time = gl841_exposure_time(dev, sensor, motor_profile, slope_dpi, + session.pixel_startx, session.optical_pixels); gl841_init_optical_regs_scan(dev, sensor, reg, exposure_time, session); move = session.params.starty; - DBG(DBG_info, "%s: move=%d steps\n", __func__, move); /* subtract current head position */ move -= (dev->head_pos(ScanHeadId::PRIMARY) * session.params.yres) / dev->motor.base_ydpi; - DBG(DBG_info, "%s: move=%d steps\n", __func__, move); if (move < 0) move = 0; /* round it */ /* the move is not affected by dummy -- pierre */ -/* move = ((move + dummy) / (dummy + 1)) * (dummy + 1); - DBG(DBG_info, "%s: move=%d steps\n", __func__, move);*/ +/* move = ((move + dummy) / (dummy + 1)) * (dummy + 1);*/ if (has_flag(session.params.flags, ScanFlag::SINGLE_LINE)) { - gl841_init_motor_regs_off(reg, dev->model->is_cis ? session.output_line_count * session.params.channels - : session.output_line_count); + gl841_init_motor_regs_off(reg, session.optical_line_count); } else { - auto motor_flag = has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) ? - MotorFlag::DISABLE_BUFFER_FULL_MOVE : MotorFlag::NONE; - - gl841_init_motor_regs_scan(dev, sensor, reg, exposure_time, slope_dpi, scan_step_type, - dev->model->is_cis ? session.output_line_count * session.params.channels - : session.output_line_count, - dummy, move, motor_flag); + gl841_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure_time, + slope_dpi, session.optical_line_count, dummy, move, + session.params.flags); } - dev->read_buffer.clear(); - dev->read_buffer.alloc(session.buffer_size_read); - - build_image_pipeline(dev, session); + setup_image_pipeline(*dev, session); dev->read_active = true; @@ -1634,45 +1079,75 @@ ScanSession CommandSetGl841::calculate_scan_session(const Genesys_Device* dev, const Genesys_Sensor& sensor, const Genesys_Settings& settings) const { - int start; - - DBG(DBG_info, "%s ", __func__); + DBG_HELPER(dbg); debug_dump(DBG_info, settings); -/* start */ - start = static_cast(dev->model->x_offset); - start += static_cast(settings.tl_x); - - start = static_cast((start * sensor.optical_res) / MM_PER_INCH); - - ScanSession session; - session.params.xres = settings.xres; - session.params.yres = settings.yres; - session.params.startx = start; - session.params.starty = 0; // not used - session.params.pixels = settings.pixels; - session.params.requested_pixels = settings.requested_pixels; - session.params.lines = settings.lines; - session.params.depth = settings.depth; - session.params.channels = settings.get_channels(); - session.params.scan_method = settings.scan_method; - session.params.scan_mode = settings.scan_mode; - session.params.color_filter = settings.color_filter; - session.params.flags = ScanFlag::NONE; - - compute_session(dev, session, sensor); + /* steps to move to reach scanning area: + - first we move to physical start of scanning + either by a fixed steps amount from the black strip + or by a fixed amount from parking position, + minus the steps done during shading calibration + - then we move by the needed offset whitin physical + scanning area + + assumption: steps are expressed at maximum motor resolution + + we need: + float y_offset; + float y_size; + float y_offset_calib; + mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH + */ + float move = dev->model->y_offset; + move += dev->settings.tl_y; - return session; -} + int move_dpi = dev->motor.base_ydpi; + move = static_cast((move * move_dpi) / MM_PER_INCH); -// for fast power saving methods only, like disabling certain amplifiers -void CommandSetGl841::save_power(Genesys_Device* dev, bool enable) const -{ - DBG_HELPER_ARGS(dbg, "enable = %d", enable); + float start = dev->model->x_offset; + start += dev->settings.tl_x; + start = static_cast((start * dev->settings.xres) / MM_PER_INCH); - const auto& sensor = sanei_genesys_find_sensor_any(dev); + // we enable true gray for cis scanners only, and just when doing + // scan since color calibration is OK for this mode + ScanFlag flags = ScanFlag::NONE; - if (enable) + // true gray (led add for cis scanners) + if (dev->model->is_cis && dev->settings.true_gray && + dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS && + dev->model->sensor_id != SensorId::CIS_CANON_LIDE_80) + { + // on Lide 80 the LEDADD bit results in only red LED array being lit + flags |= ScanFlag::ENABLE_LEDADD; + } + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = static_cast(start); + session.params.starty = static_cast(move); + session.params.pixels = dev->settings.pixels; + session.params.requested_pixels = dev->settings.requested_pixels; + session.params.lines = dev->settings.lines; + session.params.depth = dev->settings.depth; + session.params.channels = dev->settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + compute_session(dev, session, sensor); + + return session; +} + +// for fast power saving methods only, like disabling certain amplifiers +void CommandSetGl841::save_power(Genesys_Device* dev, bool enable) const +{ + DBG_HELPER_ARGS(dbg, "enable = %d", enable); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + if (enable) { if (dev->model->gpio_id == GpioId::CANON_LIDE_35) { @@ -1709,7 +1184,7 @@ void CommandSetGl841::save_power(Genesys_Device* dev, bool enable) const uint8_t val = dev->interface->read_register(REG_0x6B); dev->interface->write_register(REG_0x6B, val & ~REG_0x6B_GPO17); dev->reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17; - dev->calib_reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17; + dev->initial_regs.find_reg(0x6b).value &= ~REG_0x6B_GPO17; } set_fe(dev, sensor, AFE_POWER_SAVE); @@ -1741,13 +1216,13 @@ void CommandSetGl841::save_power(Genesys_Device* dev, bool enable) const val = dev->interface->read_register(REG_0x6B); dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO17); dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17; - dev->calib_reg.find_reg(0x6b).value |= REG_0x6B_GPO17; + dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO17; /*enable GPO18*/ val = dev->interface->read_register(REG_0x6B); dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO18); dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO18; - dev->calib_reg.find_reg(0x6b).value |= REG_0x6B_GPO18; + dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO18; } if (dev->model->gpio_id == GpioId::DP665 @@ -1756,7 +1231,7 @@ void CommandSetGl841::save_power(Genesys_Device* dev, bool enable) const uint8_t val = dev->interface->read_register(REG_0x6B); dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO17); dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17; - dev->calib_reg.find_reg(0x6b).value |= REG_0x6B_GPO17; + dev->initial_regs.find_reg(0x6b).value |= REG_0x6B_GPO17; } } @@ -1826,47 +1301,6 @@ void CommandSetGl841::set_powersaving(Genesys_Device* dev, int delay /* in minut dev->interface->write_registers(local_reg); } -static void gl841_stop_action(Genesys_Device* dev) -{ - DBG_HELPER(dbg); - Genesys_Register_Set local_reg; - unsigned int loop; - - scanner_read_print_status(*dev); - - if (scanner_is_motor_stopped(*dev)) { - DBG(DBG_info, "%s: already stopped\n", __func__); - return; - } - - local_reg = dev->reg; - - regs_set_optical_off(dev->model->asic_type, local_reg); - - gl841_init_motor_regs_off(&local_reg,0); - dev->interface->write_registers(local_reg); - - if (is_testing_mode()) { - return; - } - - /* looks like writing the right registers to zero is enough to get the chip - out of scan mode into command mode, actually triggering(writing to - register 0x0f) seems to be unnecessary */ - - loop = 10; - while (loop > 0) { - if (scanner_is_motor_stopped(*dev)) { - return; - } - - dev->interface->sleep_ms(100); - loop--; - } - - throw SaneException(SANE_STATUS_IO_ERROR, "could not stop motor"); -} - static bool gl841_get_paper_sensor(Genesys_Device* dev) { DBG_HELPER(dbg); @@ -1886,7 +1320,6 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const if (!dev->model->is_sheetfed) { DBG(DBG_proc, "%s: there is no \"eject sheet\"-concept for non sheet fed\n", __func__); - DBG(DBG_proc, "%s: finished\n", __func__); return; } @@ -1895,22 +1328,21 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const // FIXME: unused result scanner_read_status(*dev); - - gl841_stop_action(dev); + scanner_stop_action(*dev); local_reg = dev->reg; regs_set_optical_off(dev->model->asic_type, local_reg); const auto& sensor = sanei_genesys_find_sensor_any(dev); - gl841_init_motor_regs(dev, sensor, &local_reg, 65536, MOTOR_ACTION_FEED, MotorFlag::NONE); + gl841_init_motor_regs_feed(dev, sensor, &local_reg, 65536, ScanFlag::NONE); dev->interface->write_registers(local_reg); try { scanner_start_action(*dev, true); } catch (...) { - catch_all_exceptions(__func__, [&]() { gl841_stop_action(dev); }); + catch_all_exceptions(__func__, [&]() { scanner_stop_action(*dev); }); // restore original registers catch_all_exceptions(__func__, [&]() { @@ -1921,7 +1353,7 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const if (is_testing_mode()) { dev->interface->test_checkpoint("eject_document"); - gl841_stop_action(dev); + scanner_stop_action(*dev); return; } @@ -1936,10 +1368,9 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const { if (!gl841_get_paper_sensor(dev)) { - DBG(DBG_info, "%s: reached home position\n", __func__); - DBG(DBG_proc, "%s: finished\n", __func__); - break; - } + DBG(DBG_info, "%s: reached home position\n", __func__); + break; + } dev->interface->sleep_ms(100); --loop; } @@ -1948,16 +1379,15 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const { // when we come here then the scanner needed too much time for this, so we better stop // the motor - catch_all_exceptions(__func__, [&](){ gl841_stop_action(dev); }); + catch_all_exceptions(__func__, [&](){ scanner_stop_action(*dev); }); throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home"); } } - feed_mm = static_cast(dev->model->eject_feed); - if (dev->document) - { - feed_mm += static_cast(dev->model->post_scan); + feed_mm = dev->model->eject_feed; + if (dev->document) { + feed_mm += dev->model->post_scan; } sanei_genesys_read_feed_steps(dev, &init_steps); @@ -1981,11 +1411,22 @@ void CommandSetGl841::eject_document(Genesys_Device* dev) const ++loop; } - gl841_stop_action(dev); + scanner_stop_action(*dev); dev->document = false; } +void CommandSetGl841::update_home_sensor_gpio(Genesys_Device& dev) const +{ + if (dev.model->gpio_id == GpioId::CANON_LIDE_35) { + dev.interface->read_register(REG_0x6C); + dev.interface->write_register(REG_0x6C, dev.gpo.regs.get_value(0x6c)); + } + if (dev.model->gpio_id == GpioId::CANON_LIDE_80) { + dev.interface->read_register(REG_0x6B); + dev.interface->write_register(REG_0x6B, REG_0x6B_GPO18 | REG_0x6B_GPO17); + } +} void CommandSetGl841::load_document(Genesys_Device* dev) const { @@ -2064,8 +1505,6 @@ void CommandSetGl841::detect_document_end(Genesys_Device* dev) const auto skip_lines = scan_end_lines - output_lines; if (remaining_lines > skip_lines) { - DBG(DBG_io, "%s: skip_lines=%zu\n", __func__, skip_lines); - remaining_lines -= skip_lines; dev->get_pipeline_source().set_remaining_bytes(remaining_lines * dev->session.output_line_bytes_raw); @@ -2092,6 +1531,21 @@ void CommandSetGl841::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens dev->interface->write_register(REG_0x6B, val); } + if (dev->model->model_id == ModelId::CANON_LIDE_50 || + dev->model->model_id == ModelId::CANON_LIDE_60) + { + if (dev->session.params.yres >= 1200) { + dev->interface->write_register(REG_0x6C, 0x82); + } else { + dev->interface->write_register(REG_0x6C, 0x02); + } + if (dev->session.params.yres >= 600) { + dev->interface->write_register(REG_0x6B, 0x01); + } else { + dev->interface->write_register(REG_0x6B, 0x03); + } + } + if (dev->model->sensor_id != SensorId::CCD_PLUSTEK_OPTICPRO_3600) { local_reg.init_reg(0x03, reg->get8(0x03) | REG_0x03_LAMPPWR); } else { @@ -2123,732 +1577,133 @@ void CommandSetGl841::end_scan(Genesys_Device* dev, Genesys_Register_Set __sane_ DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop); if (!dev->model->is_sheetfed) { - gl841_stop_action(dev); - } -} - -// Moves the slider to steps -static void gl841_feed(Genesys_Device* dev, int steps) -{ - DBG_HELPER_ARGS(dbg, "steps = %d", steps); - Genesys_Register_Set local_reg; - int loop; - - gl841_stop_action(dev); - - // FIXME: we should pick sensor according to the resolution scanner is currently operating on - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - local_reg = dev->reg; - - regs_set_optical_off(dev->model->asic_type, local_reg); - - gl841_init_motor_regs(dev, sensor, &local_reg, steps, MOTOR_ACTION_FEED, MotorFlag::NONE); - - dev->interface->write_registers(local_reg); - - try { - scanner_start_action(*dev, true); - } catch (...) { - catch_all_exceptions(__func__, [&]() { gl841_stop_action (dev); }); - // restore original registers - catch_all_exceptions(__func__, [&]() - { - dev->interface->write_registers(dev->reg); - }); - throw; - } - - if (is_testing_mode()) { - dev->interface->test_checkpoint("feed"); - dev->advance_head_pos_by_steps(ScanHeadId::PRIMARY, Direction::FORWARD, steps); - gl841_stop_action(dev); - return; + scanner_stop_action(*dev); } - - loop = 0; - while (loop < 300) /* do not wait longer then 30 seconds */ - { - auto status = scanner_read_status(*dev); - - if (!status.is_motor_enabled) { - DBG(DBG_proc, "%s: finished\n", __func__); - dev->advance_head_pos_by_steps(ScanHeadId::PRIMARY, Direction::FORWARD, steps); - return; - } - dev->interface->sleep_ms(100); - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl841_stop_action (dev); - - dev->set_head_pos_unknown(); - - throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home"); } // Moves the slider to the home (top) position slowly void CommandSetGl841::move_back_home(Genesys_Device* dev, bool wait_until_home) const { - DBG_HELPER_ARGS(dbg, "wait_until_home = %d", wait_until_home); - Genesys_Register_Set local_reg; - int loop = 0; - - if (dev->model->is_sheetfed) { - DBG(DBG_proc, "%s: there is no \"home\"-concept for sheet fed\n", __func__); - DBG(DBG_proc, "%s: finished\n", __func__); - return; - } - - // reset gpio pin - uint8_t val; - if (dev->model->gpio_id == GpioId::CANON_LIDE_35) { - val = dev->interface->read_register(REG_0x6C); - val = dev->gpo.regs.get_value(0x6c); - dev->interface->write_register(REG_0x6C, val); - } - if (dev->model->gpio_id == GpioId::CANON_LIDE_80) { - val = dev->interface->read_register(REG_0x6B); - val = REG_0x6B_GPO18 | REG_0x6B_GPO17; - dev->interface->write_register(REG_0x6B, val); - } - dev->cmd_set->save_power(dev, false); - - // first read gives HOME_SENSOR true - auto status = scanner_read_reliable_status(*dev); - - - if (status.is_at_home) { - DBG(DBG_info, "%s: already at home, completed\n", __func__); - dev->set_head_pos_zero(ScanHeadId::PRIMARY); - return; - } - - scanner_stop_action_no_move(*dev, dev->reg); - - /* if motor is on, stop current action */ - if (status.is_motor_enabled) { - gl841_stop_action(dev); - } - - local_reg = dev->reg; - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - gl841_init_motor_regs(dev, sensor, &local_reg, 65536, MOTOR_ACTION_GO_HOME, MotorFlag::REVERSE); - - // set up for no scan - regs_set_optical_off(dev->model->asic_type, local_reg); - - dev->interface->write_registers(local_reg); - - try { - scanner_start_action(*dev, true); - } catch (...) { - catch_all_exceptions(__func__, [&]() { gl841_stop_action(dev); }); - // restore original registers - catch_all_exceptions(__func__, [&]() - { - dev->interface->write_registers(dev->reg); - }); - throw; - } - - if (is_testing_mode()) { - dev->interface->test_checkpoint("move_back_home"); - dev->set_head_pos_zero(ScanHeadId::PRIMARY); - return; - } - - if (wait_until_home) - { - while (loop < 300) /* do not wait longer then 30 seconds */ - { - auto status = scanner_read_status(*dev); - if (status.is_at_home) { - DBG(DBG_info, "%s: reached home position\n", __func__); - DBG(DBG_proc, "%s: finished\n", __func__); - dev->set_head_pos_zero(ScanHeadId::PRIMARY); - return; - } - dev->interface->sleep_ms(100); - ++loop; - } - - // when we come here then the scanner needed too much time for this, so we better stop - // the motor - catch_all_exceptions(__func__, [&](){ gl841_stop_action(dev); }); - dev->set_head_pos_unknown(); - throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home"); - } - - DBG(DBG_info, "%s: scanhead is still moving\n", __func__); + scanner_move_back_home(*dev, wait_until_home); } -// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi -// from very top of scanner -void CommandSetGl841::search_start_position(Genesys_Device* dev) const +// init registers for shading calibration +void CommandSetGl841::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const { DBG_HELPER(dbg); - int size; - Genesys_Register_Set local_reg; - - int pixels = 600; - int dpi = 300; - - local_reg = dev->reg; - /* sets for a 200 lines * 600 pixels */ - /* normal scan with no shading */ + unsigned channels = 3; - // FIXME: the current approach of doing search only for one resolution does not work on scanners - // whith employ different sensors with potentially different settings. - const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method); + unsigned resolution = sensor.shading_resolution; + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, + dev->settings.scan_method); + unsigned calib_lines = + static_cast(dev->model->y_size_calib_dark_white_mm * resolution / MM_PER_INCH); + unsigned starty = + static_cast(dev->model->y_offset_calib_dark_white_mm * dev->motor.base_ydpi / MM_PER_INCH); ScanSession session; - session.params.xres = dpi; - session.params.yres = dpi; + session.params.xres = resolution; + session.params.yres = resolution; session.params.startx = 0; - session.params.starty = 0; /*we should give a small offset here~60 steps*/ - session.params.pixels = 600; - session.params.lines = dev->model->search_lines; - session.params.depth = 8; - session.params.channels = 1; + session.params.starty = starty; + session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH; + session.params.lines = calib_lines; + session.params.depth = 16; + session.params.channels = channels; session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::GRAY; - session.params.color_filter = ColorFilter::GREEN; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; session.params.flags = ScanFlag::DISABLE_SHADING | - ScanFlag::DISABLE_GAMMA | - ScanFlag::IGNORE_LINE_DISTANCE | - ScanFlag::DISABLE_BUFFER_FULL_MOVE; - compute_session(dev, session, sensor); - - init_regs_for_scan_session(dev, sensor, &local_reg, session); - - // send to scanner - dev->interface->write_registers(local_reg); + ScanFlag::DISABLE_GAMMA; + compute_session(dev, session, calib_sensor); - size = pixels * dev->model->search_lines; + init_regs_for_scan_session(dev, calib_sensor, ®s, session); - std::vector data(size); + dev->calib_session = session; +} - dev->cmd_set->begin_scan(dev, sensor, &local_reg, true); +// this function sends generic gamma table (ie linear ones) or the Sensor specific one if provided +void CommandSetGl841::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + DBG_HELPER(dbg); + int size; - if (is_testing_mode()) { - dev->interface->test_checkpoint("search_start_position"); - dev->cmd_set->end_scan(dev, &local_reg, true); - dev->reg = local_reg; - return; - } + size = 256; - wait_until_buffer_non_empty(dev); + /* allocate temporary gamma tables: 16 bits words, 3 channels */ + std::vector gamma(size * 2 * 3); - // now we're on target, we can read data - sanei_genesys_read_data_from_scanner(dev, data.data(), size); + sanei_genesys_generate_gamma_buffer(dev, sensor, 16, 65535, size, gamma.data()); - if (DBG_LEVEL >= DBG_data) { - sanei_genesys_write_pnm_file("gl841_search_position.pnm", data.data(), 8, 1, pixels, - dev->model->search_lines); - } + dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3); +} - dev->cmd_set->end_scan(dev, &local_reg, true); - /* update regs to copy ASIC internal state */ - dev->reg = local_reg; +/* this function does the led calibration by scanning one line of the calibration + area below scanner's top on white strip. - for (auto& sensor_update : - sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method)) - { - sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels, - dev->model->search_lines); - } +-needs working coarse/gain +*/ +SensorExposure CommandSetGl841::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + return scanner_led_calibration(*dev, sensor, regs); } -// sets up register for coarse gain calibration -// todo: check it for scanners using it -void CommandSetGl841::init_regs_for_coarse_calibration(Genesys_Device* dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) const +/** @brief calibration for AD frontend devices + * offset calibration assumes that the scanning head is on a black area + * For LiDE80 analog frontend + * 0x0003 : is gain and belongs to [0..63] + * 0x0006 : is offset + * We scan a line with no gain until average offset reaches the target + */ +static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) { DBG_HELPER(dbg); + int average; + int turn; + int top; + int bottom; + int target; + + /* don't impact 3600 behavior since we can't test it */ + if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) { + return; + } + + unsigned resolution = sensor.shading_resolution; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3, + dev->settings.scan_method); + unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH; ScanSession session; - session.params.xres = dev->settings.xres; + session.params.xres = resolution; session.params.yres = dev->settings.yres; session.params.startx = 0; session.params.starty = 0; - session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel(); - session.params.lines = 20; - session.params.depth = 16; - session.params.channels = dev->settings.get_channels(); + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 8; + session.params.channels = 3; session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = dev->settings.scan_mode; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; session.params.color_filter = dev->settings.color_filter; session.params.flags = ScanFlag::DISABLE_SHADING | ScanFlag::DISABLE_GAMMA | ScanFlag::SINGLE_LINE | - ScanFlag::IGNORE_LINE_DISTANCE; - compute_session(dev, session, sensor); - - init_regs_for_scan_session(dev, sensor, ®s, session); + ScanFlag::IGNORE_STAGGER_OFFSET | + ScanFlag::IGNORE_COLOR_OFFSET; + compute_session(dev, session, calib_sensor); - DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, - sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres); + dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, ®s, session); - dev->interface->write_registers(regs); - -/* if (DBG_LEVEL >= DBG_info) - sanei_gl841_print_registers (regs);*/ -} - - -// init registers for shading calibration -void CommandSetGl841::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) const -{ - DBG_HELPER_ARGS(dbg, "lines = %zu", dev->calib_lines); - SANE_Int ydpi; - unsigned starty = 0; - - /* initial calibration reg values */ - regs = dev->reg; - - ydpi = dev->motor.base_ydpi; - if (dev->model->motor_id == MotorId::PLUSTEK_OPTICPRO_3600) /* TODO PLUSTEK_3600: 1200dpi not yet working, produces dark bar */ - { - ydpi = 600; - } - if (dev->model->motor_id == MotorId::CANON_LIDE_80) { - ydpi = gl841_get_dpihw(dev); - /* get over extra dark area for this model. - It looks like different devices have dark areas of different width - due to manufacturing variability. The initial value of starty was 140, - but it moves the sensor almost past the dark area completely in places - on certain devices. - - On a particular device the black area starts at roughly position - 160 to 230 depending on location (the dark area is not completely - parallel to the frame). - */ - starty = 70; - } - - dev->calib_channels = 3; - dev->calib_lines = dev->model->shading_lines; - - unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres); - unsigned factor = sensor.optical_res / resolution; - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, dev->calib_channels, - dev->settings.scan_method); - - dev->calib_pixels = calib_sensor.sensor_pixels / factor; - - ScanSession session; - session.params.xres = resolution; - session.params.yres = ydpi; - session.params.startx = 0; - session.params.starty = starty; - session.params.pixels = dev->calib_pixels; - session.params.lines = dev->calib_lines; - session.params.depth = 16; - session.params.channels = dev->calib_channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = ScanFlag::DISABLE_SHADING | - ScanFlag::DISABLE_GAMMA | - /*ScanFlag::DISABLE_BUFFER_FULL_MOVE |*/ - ScanFlag::IGNORE_LINE_DISTANCE; - compute_session(dev, session, calib_sensor); - - init_regs_for_scan_session(dev, calib_sensor, ®s, session); - - dev->interface->write_registers(regs); -} - -// set up registers for the actual scan -void CommandSetGl841::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const -{ - DBG_HELPER(dbg); - float move; - int move_dpi; - float start; - - debug_dump(DBG_info, dev->settings); - - /* steps to move to reach scanning area: - - first we move to physical start of scanning - either by a fixed steps amount from the black strip - or by a fixed amount from parking position, - minus the steps done during shading calibration - - then we move by the needed offset whitin physical - scanning area - - assumption: steps are expressed at maximum motor resolution - - we need: - float y_offset; - float y_size; - float y_offset_calib; - mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ - - /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is - relative from origin, else, it is from parking position */ - - move_dpi = dev->motor.base_ydpi; - - move = 0; - if (dev->model->flags & GENESYS_FLAG_SEARCH_START) { - move += static_cast(dev->model->y_offset_calib_white); - } - - DBG(DBG_info, "%s move=%f steps\n", __func__, move); - - move += static_cast(dev->model->y_offset); - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - move += static_cast(dev->settings.tl_y); - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - move = static_cast((move * move_dpi) / MM_PER_INCH); - -/* start */ - start = static_cast(dev->model->x_offset); - - start += static_cast(dev->settings.tl_x); - - start = static_cast((start * sensor.optical_res) / MM_PER_INCH); - - /* we enable true gray for cis scanners only, and just when doing - * scan since color calibration is OK for this mode - */ - ScanFlag flags = ScanFlag::NONE; - - /* true gray (led add for cis scanners) */ - if(dev->model->is_cis && dev->settings.true_gray - && dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS - && dev->model->sensor_id != SensorId::CIS_CANON_LIDE_80) - { - // on Lide 80 the LEDADD bit results in only red LED array being lit - DBG(DBG_io, "%s: activating LEDADD\n", __func__); - flags |= ScanFlag::ENABLE_LEDADD; - } - - ScanSession session; - session.params.xres = dev->settings.xres; - session.params.yres = dev->settings.yres; - session.params.startx = static_cast(start); - session.params.starty = static_cast(move); - session.params.pixels = dev->settings.pixels; - session.params.requested_pixels = dev->settings.requested_pixels; - session.params.lines = dev->settings.lines; - session.params.depth = dev->settings.depth; - session.params.channels = dev->settings.get_channels(); - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = dev->settings.scan_mode; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = flags; - compute_session(dev, session, sensor); - - init_regs_for_scan_session(dev, sensor, &dev->reg, session); -} - - -// this function sends generic gamma table (ie linear ones) or the Sensor specific one if provided -void CommandSetGl841::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const -{ - DBG_HELPER(dbg); - int size; - - size = 256; - - /* allocate temporary gamma tables: 16 bits words, 3 channels */ - std::vector gamma(size * 2 * 3); - - sanei_genesys_generate_gamma_buffer(dev, sensor, 16, 65535, size, gamma.data()); - - dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3); -} - - -/* this function does the led calibration by scanning one line of the calibration - area below scanner's top on white strip. - --needs working coarse/gain -*/ -SensorExposure CommandSetGl841::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) const -{ - DBG_HELPER(dbg); - int num_pixels; - int total_size; - int i, j; - int val; - int channels; - int avg[3], avga, avge; - int turn; - uint16_t exp[3], target; - int move; - - /* these 2 boundaries should be per sensor */ - uint16_t min_exposure=500; - uint16_t max_exposure; - - /* feed to white strip if needed */ - if (dev->model->y_offset_calib_white > 0) { - move = static_cast(dev->model->y_offset_calib_white); - move = static_cast((move * (dev->motor.base_ydpi)) / MM_PER_INCH); - DBG(DBG_io, "%s: move=%d lines\n", __func__, move); - gl841_feed(dev, move); - } - - /* offset calibration is always done in color mode */ - channels = 3; - - unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres); - unsigned factor = sensor.optical_res / resolution; - - const auto& calib_sensor_base = sanei_genesys_find_sensor(dev, resolution, channels, - dev->settings.scan_method); - - num_pixels = calib_sensor_base.sensor_pixels / factor; - - ScanSession session; - session.params.xres = resolution; - session.params.yres = dev->settings.yres; - session.params.startx = 0; - session.params.starty = 0; - session.params.pixels = num_pixels; - session.params.lines = 1; - session.params.depth = 16; - session.params.channels = channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = ScanFlag::DISABLE_SHADING | - ScanFlag::DISABLE_GAMMA | - ScanFlag::SINGLE_LINE | - ScanFlag::IGNORE_LINE_DISTANCE; - compute_session(dev, session, calib_sensor_base); - - init_regs_for_scan_session(dev, calib_sensor_base, ®s, session); - - dev->interface->write_registers(regs); - - - total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */ - - std::vector line(total_size); - -/* - we try to get equal bright leds here: - - loop: - average per color - adjust exposure times - */ - - exp[0] = sensor.exposure.red; - exp[1] = sensor.exposure.green; - exp[2] = sensor.exposure.blue; - - turn = 0; - /* max exposure is set to ~2 time initial average - * exposure, or 2 time last calibration exposure */ - max_exposure=((exp[0]+exp[1]+exp[2])/3)*2; - target=sensor.gain_white_ref*256; - - auto calib_sensor = calib_sensor_base; - - bool acceptable = false; - do { - calib_sensor.exposure.red = exp[0]; - calib_sensor.exposure.green = exp[1]; - calib_sensor.exposure.blue = exp[2]; - - regs_set_exposure(dev->model->asic_type, regs, calib_sensor.exposure); - dev->interface->write_register(0x10, (calib_sensor.exposure.red >> 8) & 0xff); - dev->interface->write_register(0x11, calib_sensor.exposure.red & 0xff); - dev->interface->write_register(0x12, (calib_sensor.exposure.green >> 8) & 0xff); - dev->interface->write_register(0x13, calib_sensor.exposure.green & 0xff); - dev->interface->write_register(0x14, (calib_sensor.exposure.blue >> 8) & 0xff); - dev->interface->write_register(0x15, calib_sensor.exposure.blue & 0xff); - - dev->interface->write_registers(regs); - - DBG(DBG_info, "%s: starting line reading\n", __func__); - dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); - - if (is_testing_mode()) { - dev->interface->test_checkpoint("led_calibration"); - move_back_home(dev, true); - return calib_sensor.exposure; - } - - sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); - - if (DBG_LEVEL >= DBG_data) { - char fn[30]; - std::snprintf(fn, 30, "gl841_led_%d.pnm", turn); - sanei_genesys_write_pnm_file(fn, line.data(), 16, channels, num_pixels, 1); - } - - /* compute average */ - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= num_pixels; - } - - DBG(DBG_info,"%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); - - acceptable = true; - - /* exposure is acceptable if each color is in the %5 range - * of other color channels */ - if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 || - avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 || - avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95) - { - acceptable = false; - } - - /* led exposure is not acceptable if white level is too low - * ~80 hardcoded value for white level */ - if(avg[0]<20000 || avg[1]<20000 || avg[2]<20000) - { - acceptable = false; - } - - /* for scanners using target value */ - if(target>0) - { - acceptable = true; - for(i=0;i<3;i++) - { - /* we accept +- 2% delta from target */ - if(abs(avg[i]-target)>target/50) - { - exp[i]=(exp[i]*target)/avg[i]; - acceptable = false; - } - } - } - else - { - if (!acceptable) - { - avga = (avg[0]+avg[1]+avg[2])/3; - exp[0] = (exp[0] * avga) / avg[0]; - exp[1] = (exp[1] * avga) / avg[1]; - exp[2] = (exp[2] * avga) / avg[2]; - /* - keep the resulting exposures below this value. - too long exposure drives the ccd into saturation. - we may fix this by relying on the fact that - we get a striped scan without shading, by means of - statistical calculation - */ - avge = (exp[0] + exp[1] + exp[2]) / 3; - - if (avge > max_exposure) { - exp[0] = (exp[0] * max_exposure) / avge; - exp[1] = (exp[1] * max_exposure) / avge; - exp[2] = (exp[2] * max_exposure) / avge; - } - if (avge < min_exposure) { - exp[0] = (exp[0] * min_exposure) / avge; - exp[1] = (exp[1] * min_exposure) / avge; - exp[2] = (exp[2] * min_exposure) / avge; - } - - } - } - - gl841_stop_action(dev); - - turn++; - - } while (!acceptable && turn < 100); - - DBG(DBG_info,"%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); - - dev->cmd_set->move_back_home(dev, true); - - return calib_sensor.exposure; -} - -/** @brief calibration for AD frontend devices - * offset calibration assumes that the scanning head is on a black area - * For LiDE80 analog frontend - * 0x0003 : is gain and belongs to [0..63] - * 0x0006 : is offset - * We scan a line with no gain until average offset reaches the target - */ -static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - DBG_HELPER(dbg); - int num_pixels; - int total_size; - int i; - int average; - int turn; - int top; - int bottom; - int target; - - /* don't impact 3600 behavior since we can't test it */ - if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) { - return; - } - - unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres); - unsigned factor = sensor.optical_res / resolution; - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3, - dev->settings.scan_method); - - num_pixels = calib_sensor.sensor_pixels / factor; - - ScanSession session; - session.params.xres = resolution; - session.params.yres = dev->settings.yres; - session.params.startx = 0; - session.params.starty = 0; - session.params.pixels = num_pixels; - session.params.lines = 1; - session.params.depth = 8; - session.params.channels = 3; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = ScanFlag::DISABLE_SHADING | - ScanFlag::DISABLE_GAMMA | - ScanFlag::SINGLE_LINE | - ScanFlag::IGNORE_LINE_DISTANCE; - compute_session(dev, session, calib_sensor); - - dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, ®s, session); - - total_size = num_pixels * 3 * 2 * 1; - - std::vector line(total_size); + // FIXME: we're reading twice as much data for no reason + std::size_t total_size = session.output_line_bytes * 2; + std::vector line(total_size); dev->frontend.set_gain(0, 0); dev->frontend.set_gain(1, 0); @@ -2873,23 +1728,23 @@ static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor& if (is_testing_mode()) { dev->interface->test_checkpoint("ad_fe_offset_calibration"); - gl841_stop_action(dev); + scanner_stop_action(*dev); return; } sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); - gl841_stop_action (dev); - if (DBG_LEVEL >= DBG_data) { + scanner_stop_action(*dev); + if (dbg_log_image_data()) { char fn[30]; - std::snprintf(fn, 30, "gl841_offset_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, line.data(), 8, 3, num_pixels, 1); + std::snprintf(fn, 30, "gl841_offset_%02d.tiff", turn); + write_tiff_file(fn, line.data(), 8, 3, num_pixels, 1); } /* search for minimal value */ average=0; - for(i=0;ireg.find_reg(0x04).value & REG_0x04_FESET) == 0x02) { - return ad_fe_offset_calibration(dev, sensor, regs); + ad_fe_offset_calibration(dev, sensor, regs); + return; } /* offset calibration is always done in color mode */ - channels = 3; + unsigned channels = 3; - unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres); - unsigned factor = sensor.optical_res / resolution; + unsigned resolution = sensor.shading_resolution; const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, dev->settings.scan_method); - num_pixels = calib_sensor.sensor_pixels / factor; - ScanSession session; session.params.xres = resolution; session.params.yres = dev->settings.yres; session.params.startx = 0; session.params.starty = 0; - session.params.pixels = num_pixels; + session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH; session.params.lines = 1; session.params.depth = 16; session.params.channels = channels; @@ -2970,17 +1816,13 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens session.params.flags = ScanFlag::DISABLE_SHADING | ScanFlag::DISABLE_GAMMA | ScanFlag::SINGLE_LINE | - ScanFlag::IGNORE_LINE_DISTANCE | + ScanFlag::IGNORE_STAGGER_OFFSET | + ScanFlag::IGNORE_COLOR_OFFSET | ScanFlag::DISABLE_LAMP; compute_session(dev, session, calib_sensor); init_regs_for_scan_session(dev, calib_sensor, ®s, session); - total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */ - - std::vector first_line(total_size); - std::vector second_line(total_size); - /* scan first line of data with no offset nor gain */ /*WM8199: gain=0.73; offset=-260mV*/ /*okay. the sensor black level is now at -260mV. we only get 0 from AFE...*/ @@ -3011,12 +1853,14 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens offl[2] = 0x00; turn = 0; + Image first_line; + bool acceptable = false; do { dev->interface->write_registers(regs); - for (j=0; j < channels; j++) { + for (unsigned j = 0; j < channels; j++) { off[j] = (offh[j]+offl[j])/2; dev->frontend.set_offset(j, off[j]); } @@ -3031,57 +1875,51 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens return; } - sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size); + first_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes); - if (DBG_LEVEL >= DBG_data) { - char fn[30]; - std::snprintf(fn, 30, "gl841_offset1_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, first_line.data(), 16, channels, num_pixels, 1); - } + if (dbg_log_image_data()) { + char fn[30]; + std::snprintf(fn, 30, "gl841_offset1_%02d.tiff", turn); + write_tiff_file(fn, first_line); + } acceptable = true; - for (j = 0; j < channels; j++) - { - cmin[j] = 0; - cmax[j] = 0; + for (unsigned ch = 0; ch < channels; ch++) { + cmin[ch] = 0; + cmax[ch] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - first_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - first_line[i * 2 + j * 2 * num_pixels]; - else - val = - first_line[i * 2 * channels + 2 * j + 1] * 256 + - first_line[i * 2 * channels + 2 * j]; - if (val < 10) - cmin[j]++; - if (val > 65525) - cmax[j]++; - } + for (std::size_t x = 0; x < first_line.get_width(); x++) { + auto value = first_line.get_raw_channel(x, 0, ch); + if (value < 10) { + cmin[ch]++; + } + if (value > 65525) { + cmax[ch]++; + } + } /* TODO the DP685 has a black strip in the middle of the sensor * should be handled in a more elegant way , could be a bug */ - if (dev->model->sensor_id == SensorId::CCD_DP685) - cmin[j] -= 20; + if (dev->model->sensor_id == SensorId::CCD_DP685) { + cmin[ch] -= 20; + } - if (cmin[j] > num_pixels/100) { + if (cmin[ch] > first_line.get_width() / 100) { acceptable = false; if (dev->model->is_cis) offl[0] = off[0]; else - offl[j] = off[j]; - } - if (cmax[j] > num_pixels/100) { + offl[ch] = off[ch]; + } + if (cmax[ch] > first_line.get_width() / 100) { acceptable = false; if (dev->model->is_cis) offh[0] = off[0]; else - offh[j] = off[j]; - } - } + offh[ch] = off[ch]; + } + } DBG(DBG_info,"%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0], cmin[1], cmax[1], cmin[2], cmax[2]); @@ -3091,7 +1929,7 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens offl[2] = offl[1] = offl[0]; } - gl841_stop_action(dev); + scanner_stop_action(*dev); turn++; } while (!acceptable && turn < 100); @@ -3099,26 +1937,19 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens DBG(DBG_info,"%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); - for (j = 0; j < channels; j++) - { - off1[j] = off[j]; + for (unsigned ch = 0; ch < channels; ch++) { + off1[ch] = off[ch]; - min1[j] = 65536; + min1[ch] = 65536; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - first_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - first_line[i * 2 + j * 2 * num_pixels]; - else - val = - first_line[i * 2 * channels + 2 * j + 1] * 256 + - first_line[i * 2 * channels + 2 * j]; - if (min1[j] > val && val >= 10) - min1[j] = val; - } - } + for (std::size_t x = 0; x < first_line.get_width(); x++) { + auto value = first_line.get_raw_channel(x, 0, ch); + + if (min1[ch] > value && value >= 10) { + min1[ch] = value; + } + } + } offl[0] = off[0]; @@ -3126,64 +1957,59 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens offl[2] = off[0]; turn = 0; + Image second_line; do { - for (j=0; j < channels; j++) { + for (unsigned j=0; j < channels; j++) { off[j] = (offh[j]+offl[j])/2; dev->frontend.set_offset(j, off[j]); - } + } dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); DBG(DBG_info, "%s: starting second line reading\n", __func__); dev->interface->write_registers(regs); dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); - sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size); + second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes); - if (DBG_LEVEL >= DBG_data) { - char fn[30]; - std::snprintf(fn, 30, "gl841_offset2_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, second_line.data(), 16, channels, num_pixels, 1); - } + if (dbg_log_image_data()) { + char fn[30]; + std::snprintf(fn, 30, "gl841_offset2_%02d.tiff", turn); + write_tiff_file(fn, second_line); + } acceptable = true; - for (j = 0; j < channels; j++) - { - cmin[j] = 0; - cmax[j] = 0; + for (unsigned ch = 0; ch < channels; ch++) { + cmin[ch] = 0; + cmax[ch] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - second_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - second_line[i * 2 + j * 2 * num_pixels]; - else - val = - second_line[i * 2 * channels + 2 * j + 1] * 256 + - second_line[i * 2 * channels + 2 * j]; - if (val < 10) - cmin[j]++; - if (val > 65525) - cmax[j]++; - } + for (std::size_t x = 0; x < second_line.get_width(); x++) { + auto value = second_line.get_raw_channel(x, 0, ch); + + if (value < 10) { + cmin[ch]++; + } + if (value > 65525) { + cmax[ch]++; + } + } - if (cmin[j] > num_pixels/100) { + if (cmin[ch] > second_line.get_width() / 100) { acceptable = false; if (dev->model->is_cis) offl[0] = off[0]; else - offl[j] = off[j]; - } - if (cmax[j] > num_pixels/100) { + offl[ch] = off[ch]; + } + if (cmax[ch] > second_line.get_width() / 100) { acceptable = false; if (dev->model->is_cis) offh[0] = off[0]; else - offh[j] = off[j]; - } - } + offh[ch] = off[ch]; + } + } DBG(DBG_info, "%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0], cmin[1], cmax[1], cmin[2], cmax[2]); @@ -3193,7 +2019,7 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens offl[2] = offl[1] = offl[0]; } - gl841_stop_action(dev); + scanner_stop_action(*dev); turn++; @@ -3202,26 +2028,19 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens DBG(DBG_info, "%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); - for (j = 0; j < channels; j++) - { - off2[j] = off[j]; + for (unsigned ch = 0; ch < channels; ch++) { + off2[ch] = off[ch]; - min2[j] = 65536; + min2[ch] = 65536; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - second_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - second_line[i * 2 + j * 2 * num_pixels]; - else - val = - second_line[i * 2 * channels + 2 * j + 1] * 256 + - second_line[i * 2 * channels + 2 * j]; - if (min2[j] > val && val != 0) - min2[j] = val; - } - } + for (std::size_t x = 0; x < second_line.get_width(); x++) { + auto value = second_line.get_raw_channel(x, 0, ch); + + if (min2[ch] > value && value != 0) { + min2[ch] = value; + } + } + } DBG(DBG_info, "%s: first set: %d/%d,%d/%d,%d/%d\n", __func__, off1[0], min1[0], off1[1], min1[1], off1[2], min1[2]); @@ -3247,22 +2066,25 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens off=(min*(off1-off2)+min1*off2-off1*min2)/(min1-min2) */ - for (j = 0; j < channels; j++) - { - if (min2[j]-min1[j] == 0) { + for (unsigned ch = 0; ch < channels; ch++) { + if (min2[ch] - min1[ch] == 0) { /*TODO: try to avoid this*/ DBG(DBG_warn, "%s: difference too small\n", __func__); - if (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j] >= 0) - off[j] = 0x0000; - else - off[j] = 0xffff; - } else - off[j] = (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j])/(min1[j]-min2[j]); - if (off[j] > 255) - off[j] = 255; - if (off[j] < 0) - off[j] = 0; - dev->frontend.set_offset(j, off[j]); + if (mintgt * (off1[ch] - off2[ch]) + min1[ch] * off2[ch] - min2[ch] * off1[ch] >= 0) { + off[ch] = 0x0000; + } else { + off[ch] = 0xffff; + } + } else { + off[ch] = (mintgt * (off1[ch] - off2[ch]) + min1[ch] * off2[ch] - min2[ch] * off1[ch])/(min1[ch]-min2[ch]); + } + if (off[ch] > 255) { + off[ch] = 255; + } + if (off[ch] < 0) { + off[ch] = 0; + } + dev->frontend.set_offset(ch, off[ch]); } DBG(DBG_info, "%s: final offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); @@ -3297,171 +2119,13 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens void CommandSetGl841::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, Genesys_Register_Set& regs, int dpi) const { - DBG_HELPER_ARGS(dbg, "dpi=%d", dpi); - int num_pixels; - int total_size; - int i, j, channels; - int max[3]; - float gain[3]; - int val; - int lines=1; - int move; - - // feed to white strip if needed - if (dev->model->y_offset_calib_white > 0) { - move = static_cast(dev->model->y_offset_calib_white); - move = static_cast((move * (dev->motor.base_ydpi)) / MM_PER_INCH); - DBG(DBG_io, "%s: move=%d lines\n", __func__, move); - gl841_feed(dev, move); - } - - /* coarse gain calibration is allways done in color mode */ - channels = 3; - - unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres); - unsigned factor = sensor.optical_res / resolution; - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, - dev->settings.scan_method); - - num_pixels = calib_sensor.sensor_pixels / factor; - - ScanSession session; - session.params.xres = resolution; - session.params.yres = dev->settings.yres; - session.params.startx = 0; - session.params.starty = 0; - session.params.pixels = num_pixels; - session.params.lines = lines; - session.params.depth = 16; - session.params.channels = channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = ScanFlag::DISABLE_SHADING | - ScanFlag::DISABLE_GAMMA | - ScanFlag::SINGLE_LINE | - ScanFlag::IGNORE_LINE_DISTANCE; - compute_session(dev, session, calib_sensor); - - init_regs_for_scan_session(dev, calib_sensor, ®s, session); - - dev->interface->write_registers(regs); - - total_size = num_pixels * channels * 2 * lines; /* colors * bytes_per_color * scan lines */ - - std::vector line(total_size); - - dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); - - if (is_testing_mode()) { - dev->interface->test_checkpoint("coarse_gain_calibration"); - gl841_stop_action(dev); - move_back_home(dev, true); - return; - } - - sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl841_gain.pnm", line.data(), 16, channels, num_pixels, lines); - - /* average high level for each channel and compute gain - to reach the target code - we only use the central half of the CCD data */ - for (j = 0; j < channels; j++) - { - max[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - - if (val > max[j]) - max[j] = val; - } - - gain[j] = 65535.0f / max[j]; - - uint8_t out_gain = 0; - - if (dev->model->adc_id == AdcId::CANON_LIDE_35 || - dev->model->adc_id == AdcId::WOLFSON_XP300 || - dev->model->adc_id == AdcId::WOLFSON_DSM600) - { - gain[j] *= 0.69f; // seems we don't get the real maximum. empirically derived - if (283 - 208/gain[j] > 255) - out_gain = 255; - else if (283 - 208/gain[j] < 0) - out_gain = 0; - else - out_gain = static_cast(283 - 208 / gain[j]); - } else if (dev->model->adc_id == AdcId::CANON_LIDE_80) { - out_gain = static_cast(gain[j] * 12); - } - dev->frontend.set_gain(j, out_gain); - - DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j], - out_gain); - } - - for (j = 0; j < channels; j++) - { - if(gain[j] > 10) - { - DBG (DBG_error0, "**********************************************\n"); - DBG (DBG_error0, "**********************************************\n"); - DBG (DBG_error0, "**** ****\n"); - DBG (DBG_error0, "**** Extremely low Brightness detected. ****\n"); - DBG (DBG_error0, "**** Check the scanning head is ****\n"); - DBG (DBG_error0, "**** unlocked and moving. ****\n"); - DBG (DBG_error0, "**** ****\n"); - DBG (DBG_error0, "**********************************************\n"); - DBG (DBG_error0, "**********************************************\n"); - throw SaneException(SANE_STATUS_JAMMED, "scanning head is locked"); - } - - } - - if (dev->model->is_cis) { - uint8_t gain0 = dev->frontend.get_gain(0); - if (gain0 > dev->frontend.get_gain(1)) { - gain0 = dev->frontend.get_gain(1); - } - if (gain0 > dev->frontend.get_gain(2)) { - gain0 = dev->frontend.get_gain(2); - } - dev->frontend.set_gain(0, gain0); - dev->frontend.set_gain(1, gain0); - dev->frontend.set_gain(2, gain0); - } - - if (channels == 1) { - dev->frontend.set_gain(0, dev->frontend.get_gain(1)); - dev->frontend.set_gain(2, dev->frontend.get_gain(1)); - } - - DBG(DBG_info, "%s: gain=(%d,%d,%d)\n", __func__, - dev->frontend.get_gain(0), - dev->frontend.get_gain(1), - dev->frontend.get_gain(2)); - - gl841_stop_action(dev); - - dev->cmd_set->move_back_home(dev, true); + scanner_coarse_gain_calibration(*dev, sensor, regs, dpi); } // wait for lamp warmup by scanning the same line until difference // between 2 scans is below a threshold void CommandSetGl841::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set* local_reg, int* channels, - int* total_size) const + Genesys_Register_Set* local_reg) const { DBG_HELPER(dbg); int num_pixels = 4 * 300; @@ -3475,51 +2139,34 @@ void CommandSetGl841::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Se dev->frontend.set_offset(1, 0x80); dev->frontend.set_offset(2, 0x80); + auto flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_STAGGER_OFFSET | + ScanFlag::IGNORE_COLOR_OFFSET; + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + flags |= ScanFlag::USE_XPA; + } + ScanSession session; - session.params.xres = sensor.optical_res; + session.params.xres = sensor.full_resolution; session.params.yres = dev->settings.yres; session.params.startx = sensor.dummy_pixel; session.params.starty = 0; session.params.pixels = num_pixels; session.params.lines = 1; - session.params.depth = 16; - session.params.channels = *channels; + session.params.depth = dev->model->bpp_color_values.front(); + session.params.channels = 3; session.params.scan_method = dev->settings.scan_method; - if (*channels == 3) { - session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - } else { - session.params.scan_mode = ScanColorMode::GRAY; - } + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; session.params.color_filter = dev->settings.color_filter; - session.params.flags = ScanFlag::DISABLE_SHADING | - ScanFlag::DISABLE_GAMMA | - ScanFlag::SINGLE_LINE | - ScanFlag::IGNORE_LINE_DISTANCE; + session.params.flags = flags; + compute_session(dev, session, sensor); init_regs_for_scan_session(dev, sensor, local_reg, session); - - num_pixels = session.output_pixels; - - *total_size = num_pixels * 3 * 2 * 1; /* colors * bytes_per_color * scan lines */ - - dev->interface->write_registers(*local_reg); -} - - -/* - * this function moves head without scanning, forward, then backward - * so that the head goes to park position. - * as a by-product, also check for lock - */ -static void sanei_gl841_repark_head(Genesys_Device* dev) -{ - DBG_HELPER(dbg); - - gl841_feed(dev,232); - - // toggle motor flag, put an huge step number and redo move backward - dev->cmd_set->move_back_home(dev, true); } /* @@ -3528,123 +2175,9 @@ static void sanei_gl841_repark_head(Genesys_Device* dev) */ void CommandSetGl841::init(Genesys_Device* dev) const { - size_t size; - - DBG_INIT (); + DBG_INIT(); DBG_HELPER(dbg); - - dev->set_head_pos_zero(ScanHeadId::PRIMARY); - - /* Check if the device has already been initialized and powered up */ - if (dev->already_initialized) - { - auto status = scanner_read_status(*dev); - if (!status.is_replugged) { - DBG(DBG_info, "%s: already initialized\n", __func__); - return; - } - } - - dev->dark_average_data.clear(); - dev->white_average_data.clear(); - - dev->settings.color_filter = ColorFilter::RED; - - // ASIC reset - dev->interface->write_register(0x0e, 0x01); - dev->interface->write_register(0x0e, 0x00); - - /* Set default values for registers */ - gl841_init_registers (dev); - - // Write initial registers - dev->interface->write_registers(dev->reg); - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - // Set analog frontend - dev->cmd_set->set_fe(dev, sensor, AFE_INIT); - - // FIXME: move_back_home modifies dev->calib_reg and requires it to be filled - dev->calib_reg = dev->reg; - - // Move home - dev->cmd_set->move_back_home(dev, true); - - // Init shading data - sanei_genesys_init_shading_data(dev, sensor, sensor.sensor_pixels); - - /* ensure head is correctly parked, and check lock */ - if (dev->model->flags & GENESYS_FLAG_REPARK) - { - // FIXME: if repark fails, we should print an error message that the scanner is locked and - // the user should unlock the lock. We should also rethrow with SANE_STATUS_JAMMED - sanei_gl841_repark_head(dev); - } - - // send gamma tables - dev->cmd_set->send_gamma_table(dev, sensor); - - /* initial calibration reg values */ - Genesys_Register_Set& regs = dev->calib_reg; - regs = dev->reg; - - unsigned resolution = sensor.get_logical_hwdpi(300); - unsigned factor = sensor.optical_res / resolution; - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3, - dev->settings.scan_method); - - unsigned num_pixels = 16 / factor; - - ScanSession session; - session.params.xres = resolution; - session.params.yres = 300; - session.params.startx = 0; - session.params.starty = 0; - session.params.pixels = num_pixels; - session.params.lines = 1; - session.params.depth = 16; - session.params.channels = 3; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - session.params.color_filter = ColorFilter::RED; - session.params.flags = ScanFlag::DISABLE_SHADING | - ScanFlag::DISABLE_GAMMA | - ScanFlag::SINGLE_LINE | - ScanFlag::IGNORE_LINE_DISTANCE; - compute_session(dev, session, calib_sensor); - - init_regs_for_scan_session(dev, calib_sensor, ®s, session); - - dev->interface->write_registers(regs); - - size = num_pixels * 3 * 2 * 1; // colors * bytes_per_color * scan lines - - std::vector line(size); - - DBG(DBG_info, "%s: starting dummy data reading\n", __func__); - dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); - - sanei_usb_set_timeout(1000);/* 1 second*/ - - if (is_testing_mode()) { - dev->interface->test_checkpoint("init"); - } else { - // ignore errors. next read will succeed - catch_all_exceptions(__func__, - [&](){ sanei_genesys_read_data_from_scanner(dev, line.data(), size); }); - } - - sanei_usb_set_timeout(30 * 1000);/* 30 seconds*/ - - end_scan(dev, ®s, true); - - regs = dev->reg; - - // Set powersaving(default = 15 minutes) - set_powersaving(dev, 15); - dev->already_initialized = true; + sanei_genesys_asic_init(dev); } void CommandSetGl841::update_hardware_sensors(Genesys_Scanner* s) const @@ -3676,225 +2209,6 @@ void CommandSetGl841::update_hardware_sensors(Genesys_Scanner* s) const } } -/** @brief search for a full width black or white strip. - * This function searches for a black or white stripe across the scanning area. - * When searching backward, the searched area must completely be of the desired - * color since this area will be used for calibration which scans forward. - * @param dev scanner device - * @param forward true if searching forward, false if searching backward - * @param black true if searching for a black strip, false for a white strip - */ -void CommandSetGl841::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward, - bool black) const -{ - DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse"); - unsigned int pixels, lines, channels; - Genesys_Register_Set local_reg; - size_t size; - unsigned int pass, count, found, x, y, length; - char title[80]; - GenesysRegister *r; - uint8_t white_level=90; /**< default white level to detect white dots */ - uint8_t black_level=60; /**< default black level to detect black dots */ - - /* use maximum gain when doing forward white strip detection - * since we don't have calibrated the sensor yet */ - if(!black && forward) - { - dev->frontend.set_gain(0, 0xff); - dev->frontend.set_gain(1, 0xff); - dev->frontend.set_gain(2, 0xff); - } - - dev->cmd_set->set_fe(dev, sensor, AFE_SET); - gl841_stop_action(dev); - - // set up for a gray scan at lowest dpi - const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method); - unsigned dpi = resolution_settings.get_min_resolution_x(); - channels = 1; - - /* shading calibation is done with dev->motor.base_ydpi */ - /* lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; */ - lines = static_cast((10 * dpi) / MM_PER_INCH); - - pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res; - - /* 20 cm max length for calibration sheet */ - length = static_cast(((200 * dpi) / MM_PER_INCH) / lines); - - dev->set_head_pos_zero(ScanHeadId::PRIMARY); - - local_reg = dev->reg; - - ScanSession session; - session.params.xres = dpi; - session.params.yres = dpi; - session.params.startx = 0; - session.params.starty = 0; - session.params.pixels = pixels; - session.params.lines = lines; - session.params.depth = 8; - session.params.channels = channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::GRAY; - session.params.color_filter = ColorFilter::RED; - session.params.flags = ScanFlag::DISABLE_SHADING | ScanFlag::DISABLE_GAMMA; - compute_session(dev, session, sensor); - - size = pixels * channels * lines * (session.params.depth / 8); - std::vector data(size); - - init_regs_for_scan_session(dev, sensor, &local_reg, session); - - /* set up for reverse or forward */ - r = sanei_genesys_get_address(&local_reg, 0x02); - if (forward) { - r->value &= ~4; - } else { - r->value |= 4; - } - - dev->interface->write_registers(local_reg); - - dev->cmd_set->begin_scan(dev, sensor, &local_reg, true); - - if (is_testing_mode()) { - dev->interface->test_checkpoint("search_strip"); - gl841_stop_action(dev); - return; - } - - // waits for valid data - wait_until_buffer_non_empty(dev); - - // now we're on target, we can read data - sanei_genesys_read_data_from_scanner(dev, data.data(), size); - - gl841_stop_action(dev); - - pass = 0; - if (DBG_LEVEL >= DBG_data) - { - std::sprintf(title, "gl841_search_strip_%s_%s%02u.pnm", black ? "black" : "white", - forward ? "fwd" : "bwd", pass); - sanei_genesys_write_pnm_file(title, data.data(), session.params.depth, - channels, pixels, lines); - } - - /* loop until strip is found or maximum pass number done */ - found = 0; - while (pass < length && !found) - { - dev->interface->write_registers(local_reg); - - //now start scan - dev->cmd_set->begin_scan(dev, sensor, &local_reg, true); - - // waits for valid data - wait_until_buffer_non_empty(dev); - - // now we're on target, we can read data - sanei_genesys_read_data_from_scanner(dev, data.data(), size); - - gl841_stop_action (dev); - - if (DBG_LEVEL >= DBG_data) - { - std::sprintf(title, "gl841_search_strip_%s_%s%02u.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", pass); - sanei_genesys_write_pnm_file(title, data.data(), session.params.depth, - channels, pixels, lines); - } - - /* search data to find black strip */ - /* when searching forward, we only need one line of the searched color since we - * will scan forward. But when doing backward search, we need all the area of the - * same color */ - if (forward) - { - for (y = 0; y < lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > white_level) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < black_level) - { - count++; - } - } - - /* at end of line, if count >= 3%, line is not fully of the desired color - * so we must go to next line of the buffer */ - /* count*100/pixels < 3 */ - if ((count * 100) / pixels < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, - pass, y); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, - (100 * count) / pixels); - } - } - } - else /* since calibration scans are done forward, we need the whole area - to be of the required color when searching backward */ - { - count = 0; - for (y = 0; y < lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > white_level) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < black_level) - { - count++; - } - } - } - - /* at end of area, if count >= 3%, area is not fully of the desired color - * so we must go to next buffer */ - if ((count * 100) / (pixels * lines) < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, - (100 * count) / pixels); - } - } - pass++; - } - - if (found) - { - DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); - } - else - { - throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white"); - } -} - /** * Send shading calibration data. The buffer is considered to always hold values * for all the channels. @@ -3903,42 +2217,30 @@ void CommandSetGl841::send_shading_data(Genesys_Device* dev, const Genesys_Senso uint8_t* data, int size) const { DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size); - uint32_t length, x, factor, pixels, i; - uint16_t dpiset, dpihw, beginpixel; + uint32_t length, x, pixels, i; uint8_t *ptr,*src; /* old method if no SHDAREA */ if ((dev->reg.find_reg(0x01).value & REG_0x01_SHDAREA) == 0) { + // Note that this requires the sensor pixel offset to be exactly the same as to start + // reading from dummy_pixel + 1 position. dev->interface->write_buffer(0x3c, 0x0000, data, size); return; } /* data is whole line, we extract only the part for the scanned area */ length = static_cast(size / 3); - unsigned strpixel = dev->session.pixel_startx; - unsigned endpixel = dev->session.pixel_endx; - - /* compute deletion/average factor */ - dpiset = dev->reg.get16(REG_DPISET); - dpihw = gl841_get_dpihw(dev); - unsigned ccd_size_divisor = dev->session.ccd_size_divisor; - factor=dpihw/dpiset; - DBG(DBG_io2, "%s: dpihw=%d, dpiset=%d, ccd_size_divisor=%d, factor=%d\n", __func__, dpihw, dpiset, - ccd_size_divisor, factor); - - /* turn pixel value into bytes 2x16 bits words */ - strpixel*=2*2; /* 2 words of 2 bytes */ - endpixel*=2*2; - pixels=endpixel-strpixel; - - /* shading pixel begin is start pixel minus start pixel during shading - * calibration. Currently only cases handled are full and half ccd resolution. - */ - beginpixel = sensor.ccd_start_xoffset / ccd_size_divisor; - beginpixel += sensor.dummy_pixel + 1; - DBG(DBG_io2, "%s: ORIGIN PIXEL=%d\n", __func__, beginpixel); - beginpixel = (strpixel-beginpixel*2*2)/factor; - DBG(DBG_io2, "%s: BEGIN PIXEL=%d\n", __func__, beginpixel/4); + + // turn pixel value into bytes 2x16 bits words + pixels = dev->session.pixel_endx - dev->session.pixel_startx; + pixels *= 4; + + // shading pixel begin is start pixel minus start pixel during shading + // calibration. Currently only cases handled are full and half ccd resolution. + unsigned beginpixel = dev->session.params.startx * dev->session.optical_resolution / + dev->session.params.xres; + beginpixel *= 4; + beginpixel /= sensor.shading_factor; dev->interface->record_key_value("shading_offset", std::to_string(beginpixel)); dev->interface->record_key_value("shading_pixels", std::to_string(pixels)); @@ -3962,7 +2264,7 @@ void CommandSetGl841::send_shading_data(Genesys_Device* dev, const Genesys_Senso for(x=0;xinterface->write_register(0x0e, 0x01); + dev->interface->write_register(0x0e, 0x00); + } -std::unique_ptr create_gl841_cmd_set() -{ - return std::unique_ptr(new CommandSetGl841{}); + gl841_init_registers(dev); + + // Write initial registers + dev->interface->write_registers(dev->reg); + + // FIXME: 0x0b is not set, but on all other backends we do set it + // dev->reg.remove_reg(0x0b); + + if (dev->model->model_id == ModelId::CANON_LIDE_60) { + dev->interface->write_0x8c(0x10, 0xa4); + } + + // FIXME: we probably don't need this + const auto& sensor = sanei_genesys_find_sensor_any(dev); + dev->cmd_set->set_fe(dev, sensor, AFE_INIT); } } // namespace gl841 -- cgit v1.2.3