diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-24 18:44:51 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-24 18:44:51 +0200 |
commit | ad38bc6ecb80ddeb562841b33258dd53659b1da6 (patch) | |
tree | e02e9c3ff760554fd87f70df0e18b88594091a48 /backend/genesys/gl843.cpp | |
parent | 9c23ed018d72eed2554f4f9cff1ae6e6bb0cd479 (diff) |
New upstream version 1.0.31upstream/1.0.31
Diffstat (limited to 'backend/genesys/gl843.cpp')
-rw-r--r-- | backend/genesys/gl843.cpp | 1955 |
1 files changed, 341 insertions, 1614 deletions
diff --git a/backend/genesys/gl843.cpp b/backend/genesys/gl843.cpp index f83ac8d..8233bde 100644 --- a/backend/genesys/gl843.cpp +++ b/backend/genesys/gl843.cpp @@ -54,60 +54,18 @@ namespace genesys { namespace gl843 { -// Set address for writing data -static void gl843_set_buffer_address(Genesys_Device* dev, uint32_t addr) -{ - DBG_HELPER_ARGS(dbg, "setting address to 0x%05x", addr & 0xffff); - - dev->interface->write_register(0x5b, ((addr >> 8) & 0xff)); - dev->interface->write_register(0x5c, (addr & 0xff)); -} - /** * compute the step multiplier used */ static int gl843_get_step_multiplier(Genesys_Register_Set* regs) { - GenesysRegister *r = sanei_genesys_get_address(regs, REG_0x9D); - int value = 1; - if (r != nullptr) - { - switch (r->value & 0x0c) - { - case 0x04: - value = 2; - break; - case 0x08: - value = 4; - break; - default: - value = 1; - } - } - DBG(DBG_io, "%s: step multiplier is %d\n", __func__, value); - return value; -} - -/** copy sensor specific settings */ -static void gl843_setup_sensor(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set* regs) -{ - DBG_HELPER(dbg); - for (const auto& custom_reg : sensor.custom_regs) { - regs->set8(custom_reg.address, custom_reg.value); + switch (regs->get8(REG_0x9D) & 0x0c) { + case 0x04: return 2; + case 0x08: return 4; + default: return 1; } - if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE) && - dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7200I && - dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7300 && - dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7500I) - { - regs->set8(0x7d, 0x90); - } - - dev->segment_order = sensor.segment_order; } - /** @brief set all registers to default values . * This function is called only once at the beginning and * fills register startup values for registers reused across scans. @@ -118,9 +76,9 @@ static void gl843_setup_sensor(Genesys_Device* dev, const Genesys_Sensor& sensor static void gl843_init_registers (Genesys_Device * dev) { - // Within this function SENSOR_DEF marker documents that a register is part - // of the sensors definition and the actual value is set in - // gl843_setup_sensor(). + // Within this function SENSOR_DEF marker documents that a register is part + // of the sensors definition and the actual value is set in + // scanner_setup_sensor(). // 0x6c, 0x6d, 0x6e, 0x6f, 0xa6, 0xa7, 0xa8, 0xa9 are defined in the Gpo sensor struct @@ -158,8 +116,16 @@ gl843_init_registers (Genesys_Device * dev) dev->reg.init_reg(0x05, 0x08); } + auto initial_scan_method = dev->model->default_method; + if (dev->model->model_id == ModelId::CANON_4400F || + dev->model->model_id == ModelId::CANON_8600F) + { + initial_scan_method = ScanMethod::TRANSPARENCY; + } const auto& sensor = sanei_genesys_find_sensor_any(dev); - sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res); + const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, sensor.full_resolution, + 3, initial_scan_method); + sanei_genesys_set_dpihw(dev->reg, dpihw_sensor.register_dpihw); // TODO: on 8600F the windows driver turns off GAIN4 which is recommended dev->reg.init_reg(0x06, 0xd8); /* SCANMOD=110, PWRBIT and GAIN4 */ @@ -402,11 +368,11 @@ gl843_init_registers (Genesys_Device * dev) // STEPSEL[0:1]. Motor movement step mode selection for tables 1-3 in // scanning mode. // MTRPWM[0:5]. Motor phase PWM duty cycle setting for tables 1-3 - dev->reg.init_reg(0x67, 0x7f); + dev->reg.init_reg(0x67, 0x7f); // MOTOR_PROFILE // FSTPSEL[0:1]: Motor movement step mode selection for tables 4-5 in // command mode. // FASTPWM[5:0]: Motor phase PWM duty cycle setting for tables 4-5 - dev->reg.init_reg(0x68, 0x7f); + dev->reg.init_reg(0x68, 0x7f); // MOTOR_PROFILE if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300) { dev->reg.init_reg(0x67, 0x80); @@ -415,17 +381,11 @@ gl843_init_registers (Genesys_Device * dev) // FSHDEC[0:7]: The number of deceleration steps after scanning is finished // (table 3) - dev->reg.init_reg(0x69, 0x01); - if (dev->model->model_id == ModelId::CANON_8600F) { - dev->reg.init_reg(0x69, 64); - } + dev->reg.init_reg(0x69, 0x01); // MOTOR_PROFILE // FMOVNO[0:7] The number of acceleration or deceleration steps for fast // moving (table 4) - dev->reg.init_reg(0x6a, 0x04); - if (dev->model->model_id == ModelId::CANON_8600F) { - dev->reg.init_reg(0x69, 64); - } + dev->reg.init_reg(0x6a, 0x04); // MOTOR_PROFILE // GPIO-related register bits dev->reg.init_reg(0x6b, 0x30); @@ -516,7 +476,7 @@ gl843_init_registers (Genesys_Device * dev) // VRHOME, VRMOVE, VRBACK, VRSCAN: Vref settings of the motor driver IC for // moving in various situations. - dev->reg.init_reg(0x80, 0x00); + dev->reg.init_reg(0x80, 0x00); // MOTOR_PROFILE if (dev->model->model_id == ModelId::CANON_4400F) { dev->reg.init_reg(0x80, 0x0c); } @@ -632,7 +592,7 @@ gl843_init_registers (Genesys_Device * dev) dev->reg.init_reg(0xaa, 0x00); } - // GPOM9, MULSTOP[0-2], NODECEL, TB3TB1, TB5TB2, FIX16CLK. Not documented + // GPOM9, MULSTOP[0-2], NODECEL, TB3TB1, TB5TB2, FIX16CLK. if (dev->model->model_id != ModelId::CANON_8400F && dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7200I && dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7300) { @@ -643,10 +603,9 @@ gl843_init_registers (Genesys_Device * dev) } if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::CANON_8600F || dev->model->model_id == ModelId::HP_SCANJET_4850C) { - // BUG: this should apply to ModelId::CANON_CANOSCAN_8600F too, but due to previous bug - // the 8400F case overwrote it dev->reg.init_reg(0xab, 0x40); } @@ -660,8 +619,6 @@ gl843_init_registers (Genesys_Device * dev) dev->reg.init_reg(0xac, 0x00); } - dev->calib_reg = dev->reg; - if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I) { uint8_t data[32] = { 0x8c, 0x8f, 0xc9, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -670,48 +627,8 @@ gl843_init_registers (Genesys_Device * dev) 0x6a, 0x73, 0x63, 0x68, 0x69, 0x65, 0x6e, 0x00, }; - dev->interface->write_buffer(0x3c, 0x3ff000, data, 32, - ScannerInterface::FLAG_SWAP_REGISTERS); - } -} - -// Send slope table for motor movement slope_table in machine byte order -static void gl843_send_slope_table(Genesys_Device* dev, int table_nr, - const std::vector<uint16_t>& slope_table, - int steps) -{ - DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps); - - int i; - char msg[10000]; - - std::vector<uint8_t> 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); - } - - if (dev->interface->is_mock()) { - dev->interface->record_slope_table(table_nr, slope_table); + dev->interface->write_buffer(0x3c, 0x3ff000, data, 32); } - - // slope table addresses are fixed : 0x40000, 0x48000, 0x50000, 0x58000, 0x60000 - // XXX STEF XXX USB 1.1 ? sanei_genesys_write_0x8c (dev, 0x0f, 0x14); - dev->interface->write_gamma(0x28, 0x40000 + 0x8000 * table_nr, table.data(), steps * 2, - ScannerInterface::FLAG_SWAP_REGISTERS); - - // FIXME: remove this when updating tests - gl843_set_buffer_address(dev, 0); } static void gl843_set_ad_fe(Genesys_Device* dev) @@ -728,14 +645,9 @@ void CommandSetGl843::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, set == AFE_SET ? "set" : set == AFE_POWER_SAVE ? "powersave" : "huh?"); (void) sensor; - int i; - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, - static_cast<unsigned>(dev->model->adc_id)); - dev->frontend = dev->frontend_initial; - dev->frontend_is_init = true; + if (set == AFE_INIT) { + dev->frontend = dev->frontend_initial; } // check analog frontend type @@ -749,153 +661,135 @@ void CommandSetGl843::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, throw SaneException(SANE_STATUS_UNSUPPORTED, "unsupported frontend type %d", fe_type); } - DBG(DBG_proc, "%s(): frontend reset complete\n", __func__); - - for (i = 1; i <= 3; i++) - { - // FIXME: the check below is just historical artifact, we can remove it when convenient - if (!dev->frontend_is_init) { - dev->interface->write_fe_register(i, 0x00); - } else { - dev->interface->write_fe_register(i, dev->frontend.regs.get_value(0x00 + i)); - } + for (unsigned i = 1; i <= 3; i++) { + dev->interface->write_fe_register(i, dev->frontend.regs.get_value(0x00 + i)); } for (const auto& reg : sensor.custom_fe_regs) { dev->interface->write_fe_register(reg.address, reg.value); } - for (i = 0; i < 3; i++) - { - // FIXME: the check below is just historical artifact, we can remove it when convenient - if (!dev->frontend_is_init) { - dev->interface->write_fe_register(0x20 + i, 0x00); - } else { - dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i)); - } + for (unsigned i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i)); } if (dev->model->sensor_id == SensorId::CCD_KVSS080) { - for (i = 0; i < 3; i++) - { - // FIXME: the check below is just historical artifact, we can remove it when convenient - if (!dev->frontend_is_init) { - dev->interface->write_fe_register(0x24 + i, 0x00); - } else { - dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i)); - } - } + for (unsigned i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i)); + } } - for (i = 0; i < 3; i++) - { - // FIXME: the check below is just historical artifact, we can remove it when convenient - if (!dev->frontend_is_init) { - dev->interface->write_fe_register(0x28 + i, 0x00); - } else { - dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i)); - } + for (unsigned i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i)); } } - static void gl843_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + const ScanSession& session, Genesys_Register_Set* reg, - const Motor_Profile& motor_profile, + const MotorProfile& motor_profile, unsigned int exposure, unsigned scan_yres, unsigned int scan_lines, unsigned int scan_dummy, unsigned int feed_steps, - MotorFlag flags) + ScanFlag flags) { DBG_HELPER_ARGS(dbg, "exposure=%d, scan_yres=%d, step_type=%d, scan_lines=%d, scan_dummy=%d, " "feed_steps=%d, flags=%x", exposure, scan_yres, static_cast<unsigned>(motor_profile.step_type), scan_lines, scan_dummy, feed_steps, static_cast<unsigned>(flags)); - int use_fast_fed, coeff; - unsigned int lincnt; unsigned feedl, dist; - GenesysRegister *r; - uint32_t z1, z2; /* get step multiplier */ unsigned step_multiplier = gl843_get_step_multiplier (reg); - use_fast_fed = 0; + bool use_fast_fed = false; - if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, MotorFlag::FEED))) { - use_fast_fed = 1; + if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, ScanFlag::FEEDING))) { + use_fast_fed = true; + } + if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) { + use_fast_fed = false; } - lincnt=scan_lines; - reg->set24(REG_LINCNT, lincnt); - DBG(DBG_io, "%s: lincnt=%d\n", __func__, lincnt); + reg->set24(REG_LINCNT, scan_lines); - /* compute register 02 value */ - r = sanei_genesys_get_address(reg, REG_0x02); - r->value = 0x00; - sanei_genesys_set_motor_power(*reg, true); + reg->set8(REG_0x02, 0); + sanei_genesys_set_motor_power(*reg, true); + std::uint8_t reg02 = reg->get8(REG_0x02); if (use_fast_fed) { - r->value |= REG_0x02_FASTFED; + reg02 |= REG_0x02_FASTFED; } else { - r->value &= ~REG_0x02_FASTFED; + reg02 &= ~REG_0x02_FASTFED; } - /* in case of automatic go home, move until home sensor */ - if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) { - r->value |= REG_0x02_AGOHOME | REG_0x02_NOTHOME; + // in case of automatic go home, move until home sensor + if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) { + reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME; } /* disable backtracking */ - if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE) - ||(scan_yres>=2400 && dev->model->model_id != ModelId::CANON_4400F) - ||(scan_yres>=sensor.optical_res)) + if (has_flag(flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) || + (scan_yres>=2400 && dev->model->model_id != ModelId::CANON_4400F) || + (scan_yres>=sensor.full_resolution)) { - r->value |= REG_0x02_ACDCDIS; + reg02 |= REG_0x02_ACDCDIS; } - if (has_flag(flags, MotorFlag::REVERSE)) { - r->value |= REG_0x02_MTRREV; + if (has_flag(flags, ScanFlag::REVERSE)) { + reg02 |= REG_0x02_MTRREV; } else { - r->value &= ~REG_0x02_MTRREV; + reg02 &= ~REG_0x02_MTRREV; } + reg->set8(REG_0x02, reg02); - /* scan and backtracking slope table */ - auto scan_table = sanei_genesys_slope_table(dev->model->asic_type, scan_yres, exposure, - dev->motor.base_ydpi, step_multiplier, - motor_profile); + // scan and backtracking slope table + auto scan_table = create_slope_table(dev->model->asic_type, dev->motor, scan_yres, exposure, + step_multiplier, motor_profile); - gl843_send_slope_table(dev, SCAN_TABLE, scan_table.table, scan_table.steps_count); - gl843_send_slope_table(dev, BACKTRACK_TABLE, scan_table.table, scan_table.steps_count); + scanner_send_slope_table(dev, sensor, SCAN_TABLE, scan_table.table); + scanner_send_slope_table(dev, sensor, BACKTRACK_TABLE, scan_table.table); + scanner_send_slope_table(dev, sensor, STOP_TABLE, scan_table.table); - reg->set8(REG_STEPNO, scan_table.steps_count / step_multiplier); - reg->set8(REG_FASTNO, scan_table.steps_count / step_multiplier); + reg->set8(REG_STEPNO, scan_table.table.size() / step_multiplier); + reg->set8(REG_FASTNO, scan_table.table.size() / step_multiplier); + reg->set8(REG_FSHDEC, scan_table.table.size() / step_multiplier); // fast table - unsigned fast_yres = sanei_genesys_get_lowest_ydpi(dev); - auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_yres, exposure, - dev->motor.base_ydpi, step_multiplier, - motor_profile); - gl843_send_slope_table(dev, STOP_TABLE, fast_table.table, fast_table.steps_count); - gl843_send_slope_table(dev, FAST_TABLE, fast_table.table, fast_table.steps_count); - gl843_send_slope_table(dev, HOME_TABLE, fast_table.table, fast_table.steps_count); + const auto* fast_profile = get_motor_profile_ptr(dev->motor.fast_profiles, 0, session); + if (fast_profile == nullptr) { + fast_profile = &motor_profile; + } - reg->set8(REG_FSHDEC, fast_table.steps_count / step_multiplier); - reg->set8(REG_FMOVNO, fast_table.steps_count / step_multiplier); + auto fast_table = create_slope_table_fastest(dev->model->asic_type, step_multiplier, + *fast_profile); + + scanner_send_slope_table(dev, sensor, FAST_TABLE, fast_table.table); + scanner_send_slope_table(dev, sensor, HOME_TABLE, fast_table.table); + + reg->set8(REG_FMOVNO, fast_table.table.size() / step_multiplier); + + if (motor_profile.motor_vref != -1 && fast_profile->motor_vref != 1) { + std::uint8_t vref = 0; + vref |= (motor_profile.motor_vref << REG_0x80S_TABLE1_NORMAL) & REG_0x80_TABLE1_NORMAL; + vref |= (motor_profile.motor_vref << REG_0x80S_TABLE2_BACK) & REG_0x80_TABLE2_BACK; + vref |= (fast_profile->motor_vref << REG_0x80S_TABLE4_FAST) & REG_0x80_TABLE4_FAST; + vref |= (fast_profile->motor_vref << REG_0x80S_TABLE5_GO_HOME) & REG_0x80_TABLE5_GO_HOME; + reg->set8(REG_0x80, vref); + } /* substract acceleration distance from feedl */ feedl=feed_steps; feedl <<= static_cast<unsigned>(motor_profile.step_type); - dist = scan_table.steps_count / step_multiplier; - if (use_fast_fed) - { - dist += (fast_table.steps_count / step_multiplier) * 2; + dist = scan_table.table.size() / step_multiplier; + + if (use_fast_fed) { + dist += (fast_table.table.size() / step_multiplier) * 2; } - DBG(DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); /* get sure when don't insane value : XXX STEF XXX in this case we should * fall back to single table move */ @@ -906,15 +800,15 @@ static void gl843_init_motor_regs_scan(Genesys_Device* dev, } reg->set24(REG_FEEDL, feedl); - DBG(DBG_io, "%s: feedl=%d\n", __func__, feedl); - /* doesn't seem to matter that much */ + // doesn't seem to matter that much + std::uint32_t z1, z2; sanei_genesys_calculate_zmod(use_fast_fed, - exposure, + exposure, scan_table.table, - scan_table.steps_count / step_multiplier, - feedl, - scan_table.steps_count / step_multiplier, + scan_table.table.size() / step_multiplier, + feedl, + scan_table.table.size() / step_multiplier, &z1, &z2); if(scan_yres>600) @@ -924,47 +818,46 @@ static void gl843_init_motor_regs_scan(Genesys_Device* dev, } reg->set24(REG_Z1MOD, z1); - DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); - reg->set24(REG_Z2MOD, z2); - DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); - r = sanei_genesys_get_address(reg, REG_0x1E); - r->value &= 0xf0; /* 0 dummy lines */ - r->value |= scan_dummy; /* dummy lines */ + reg->set8_mask(REG_0x1E, scan_dummy, 0x0f); reg->set8_mask(REG_0x67, static_cast<unsigned>(motor_profile.step_type) << REG_0x67S_STEPSEL, 0xc0); - reg->set8_mask(REG_0x68, static_cast<unsigned>(motor_profile.step_type) << REG_0x68S_FSTPSEL, 0xc0); + reg->set8_mask(REG_0x68, static_cast<unsigned>(fast_profile->step_type) << REG_0x68S_FSTPSEL, 0xc0); // steps for STOP table - reg->set8(REG_FMOVDEC, fast_table.steps_count / step_multiplier); + reg->set8(REG_FMOVDEC, fast_table.table.size() / step_multiplier); - /* Vref XXX STEF XXX : optical divider or step type ? */ - r = sanei_genesys_get_address (reg, 0x80); - if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE)) + if (dev->model->model_id == ModelId::PANASONIC_KV_SS080 || + dev->model->model_id == ModelId::HP_SCANJET_4850C || + dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) { - r->value = 0x50; - coeff = sensor.get_hwdpi_divisor_for_dpi(scan_yres); + // FIXME: take this information from motor struct + std::uint8_t reg_vref = reg->get8(0x80); + reg_vref = 0x50; + unsigned coeff = sensor.full_resolution / scan_yres; if (dev->model->motor_id == MotorId::KVSS080) { - if(coeff>=1) - { - r->value |= 0x05; + if (coeff >= 1) { + reg_vref |= 0x05; + } + } else { + switch (coeff) { + case 4: + reg_vref |= 0x0a; + break; + case 2: + reg_vref |= 0x0f; + break; + case 1: + reg_vref |= 0x0f; + break; } } - else { - switch(coeff) - { - case 4: - r->value |= 0x0a; - break; - case 2: - r->value |= 0x0f; - break; - case 1: - r->value |= 0x0f; - break; - } - } + reg->set8(REG_0x80, reg_vref); } } @@ -981,7 +874,6 @@ static void gl843_init_motor_regs_scan(Genesys_Device* dev, * @param pixels logical number of pixels to use * @param channels number of color channles used (1 or 3) * @param depth bit depth of the scan (1, 8 or 16 bits) - * @param ccd_size_divisor true specifies how much x coordinates must be shrunk * @param color_filter to choose the color channel used in gray scans * @param flags to drive specific settings such no calibration, XPA use ... */ @@ -990,57 +882,54 @@ static void gl843_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens const ScanSession& session) { DBG_HELPER_ARGS(dbg, "exposure=%d", exposure); - unsigned int dpihw; unsigned int tgtime; /**> exposure time multiplier */ - GenesysRegister *r; /* tgtime */ tgtime = exposure / 65536 + 1; DBG(DBG_io2, "%s: tgtime=%d\n", __func__, tgtime); - // to manage high resolution device while keeping good low resolution scanning speed, we make - // hardware dpi vary - dpihw = sensor.get_register_hwdpi(session.output_resolution); - DBG(DBG_io2, "%s: dpihw=%d\n", __func__, dpihw); - - /* sensor parameters */ - gl843_setup_sensor(dev, sensor, reg); - - // resolution is divided according to CKSEL - unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel(); - DBG(DBG_io2, "%s: ccd_pixels_per_system_pixel=%d\n", __func__, ccd_pixels_per_system_pixel); + // sensor parameters + scanner_setup_sensor(*dev, sensor, *reg); dev->cmd_set->set_fe(dev, sensor, AFE_SET); /* enable shading */ regs_set_optical_off(dev->model->asic_type, *reg); - r = sanei_genesys_get_address (reg, REG_0x01); if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) || - (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION || - (dev->model->flags & GENESYS_FLAG_CALIBRATION_HOST_SIDE))) + has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) || + session.use_host_side_calib) { - r->value &= ~REG_0x01_DVDSET; + reg->find_reg(REG_0x01).value &= ~REG_0x01_DVDSET; + } else { - r->value |= REG_0x01_DVDSET; + reg->find_reg(REG_0x01).value |= REG_0x01_DVDSET; } - bool use_shdarea = dpihw > 600; + bool use_shdarea = false; if (dev->model->model_id == ModelId::CANON_4400F) { use_shdarea = session.params.xres <= 600; } else if (dev->model->model_id == ModelId::CANON_8400F) { use_shdarea = session.params.xres <= 400; + } else if (dev->model->model_id == ModelId::CANON_8600F || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) + { + use_shdarea = true; + } else { + use_shdarea = session.params.xres > 600; } + if (use_shdarea) { - r->value |= REG_0x01_SHDAREA; + reg->find_reg(REG_0x01).value |= REG_0x01_SHDAREA; } else { - r->value &= ~REG_0x01_SHDAREA; + reg->find_reg(REG_0x01).value &= ~REG_0x01_SHDAREA; } - r = sanei_genesys_get_address (reg, REG_0x03); if (dev->model->model_id == ModelId::CANON_8600F) { - r->value |= REG_0x03_AVEENB; + reg->find_reg(REG_0x03).value |= REG_0x03_AVEENB; } else { - r->value &= ~REG_0x03_AVEENB; + reg->find_reg(REG_0x03).value &= ~REG_0x03_AVEENB; } // FIXME: we probably don't need to set exposure to registers at this point. It was this way @@ -1049,43 +938,40 @@ static void gl843_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP)); /* select XPA */ - r->value &= ~REG_0x03_XPASEL; + reg->find_reg(REG_0x03).value &= ~REG_0x03_XPASEL; if (has_flag(session.params.flags, ScanFlag::USE_XPA)) { - r->value |= REG_0x03_XPASEL; + reg->find_reg(REG_0x03).value |= REG_0x03_XPASEL; } reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA); - /* BW threshold */ - r = sanei_genesys_get_address(reg, REG_0x2E); - r->value = dev->settings.threshold; - r = sanei_genesys_get_address(reg, REG_0x2F); - r->value = dev->settings.threshold; + // BW threshold + reg->set8(REG_0x2E, 0x7f); + reg->set8(REG_0x2F, 0x7f); /* monochrome / color scan */ - r = sanei_genesys_get_address(reg, REG_0x04); switch (session.params.depth) { case 8: - r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET); + reg->find_reg(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(REG_0x04).value &= ~REG_0x04_LINEART; + reg->find_reg(REG_0x04).value |= REG_0x04_BITSET; break; } - r->value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD); + reg->find_reg(REG_0x04).value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD); if (session.params.channels == 1) { switch (session.params.color_filter) { case ColorFilter::RED: - r->value |= 0x14; + reg->find_reg(REG_0x04).value |= 0x14; break; case ColorFilter::BLUE: - r->value |= 0x1c; + reg->find_reg(REG_0x04).value |= 0x1c; break; case ColorFilter::GREEN: - r->value |= 0x18; + reg->find_reg(REG_0x04).value |= 0x18; break; default: break; // should not happen @@ -1093,10 +979,10 @@ static void gl843_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens } else { switch (dev->frontend.layout.type) { case FrontendType::WOLFSON: - r->value |= 0x10; // pixel by pixel + reg->find_reg(REG_0x04).value |= 0x10; // pixel by pixel break; case FrontendType::ANALOG_DEVICES: - r->value |= 0x20; // slow color pixel by pixel + reg->find_reg(REG_0x04).value |= 0x20; // slow color pixel by pixel break; default: throw SaneException("Invalid frontend type %d", @@ -1104,7 +990,10 @@ static void gl843_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens } } - sanei_genesys_set_dpihw(*reg, sensor, dpihw); + const auto& dpihw_sensor = sanei_genesys_find_sensor(dev, session.output_resolution, + session.params.channels, + session.params.scan_method); + sanei_genesys_set_dpihw(*reg, dpihw_sensor.register_dpihw); if (should_enable_gamma(session, sensor)) { reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB; @@ -1112,28 +1001,18 @@ static void gl843_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB; } - unsigned dpiset = session.output_resolution * session.ccd_size_divisor * - ccd_pixels_per_system_pixel; - - if (sensor.dpiset_override != 0) { - dpiset = sensor.dpiset_override; - } - reg->set16(REG_DPISET, dpiset); - DBG(DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); + reg->set16(REG_DPISET, sensor.register_dpiset); reg->set16(REG_STRPIXEL, session.pixel_startx); reg->set16(REG_ENDPIXEL, session.pixel_endx); /* MAXWD is expressed in 2 words unit */ /* nousedspace = (mem_bank_range * 1024 / 256 -1 ) * 4; */ - // BUG: the division by ccd_size_divisor likely does not make sense - reg->set24(REG_MAXWD, (session.output_line_bytes / session.ccd_size_divisor) >> 1); - + // BUG: the division by optical and full resolution factor likely does not make sense + reg->set24(REG_MAXWD, (session.output_line_bytes * + session.optical_resolution / session.full_resolution) >> 1); reg->set16(REG_LPERIOD, exposure / tgtime); - DBG(DBG_io2, "%s: exposure used=%d\n", __func__, exposure/tgtime); - - r = sanei_genesys_get_address (reg, REG_DUMMY); - r->value = sensor.dummy_pixel; + reg->set8(REG_DUMMY, sensor.dummy_pixel); } void CommandSetGl843::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, @@ -1170,42 +1049,15 @@ void CommandSetGl843::init_regs_for_scan_session(Genesys_Device* dev, const Gene if (exposure < 0) { throw std::runtime_error("Exposure not defined in sensor definition"); } - const auto& motor_profile = sanei_genesys_get_motor_profile(*gl843_motor_profiles, - dev->model->motor_id, - exposure); - - DBG(DBG_info, "%s : exposure=%d pixels\n", __func__, exposure); - DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, - static_cast<unsigned>(motor_profile.step_type)); + const auto& motor_profile = get_motor_profile(dev->motor.profiles, exposure, session); // now _LOGICAL_ optical values used are known, setup registers gl843_init_optical_regs_scan(dev, sensor, reg, exposure, session); + gl843_init_motor_regs_scan(dev, sensor, session, reg, motor_profile, exposure, slope_dpi, + session.optical_line_count, dummy, session.params.starty, + session.params.flags); - /*** motor parameters ***/ - MotorFlag mflags = MotorFlag::NONE; - if (has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) { - mflags |= MotorFlag::DISABLE_BUFFER_FULL_MOVE; - } - if (has_flag(session.params.flags, ScanFlag::FEEDING)) { - mflags |= MotorFlag::FEED; - } - if (has_flag(session.params.flags, ScanFlag::USE_XPA)) { - mflags |= MotorFlag::USE_XPA; - } - if (has_flag(session.params.flags, ScanFlag::REVERSE)) { - mflags |= MotorFlag::REVERSE; - } - - unsigned scan_lines = dev->model->is_cis ? session.output_line_count * session.params.channels - : session.output_line_count; - - gl843_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure, slope_dpi, - scan_lines, dummy, session.params.starty, mflags); - - 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; @@ -1224,33 +1076,46 @@ ScanSession CommandSetGl843::calculate_scan_session(const Genesys_Device* dev, DBG_HELPER(dbg); debug_dump(DBG_info, settings); - int start; - - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - unsigned ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(settings.xres); + ScanFlag flags = ScanFlag::NONE; + float move = 0.0f; if (settings.scan_method == ScanMethod::TRANSPARENCY || settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) { - start = static_cast<int>(dev->model->x_offset_ta); + // note: scanner_move_to_ta() function has already been called and the sensor is at the + // transparency adapter + if (!dev->ignore_offsets) { + move = dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta; + } + flags |= ScanFlag::USE_XPA; } else { - start = static_cast<int>(dev->model->x_offset); + if (!dev->ignore_offsets) { + move = dev->model->y_offset; + } } - if (dev->model->model_id == ModelId::CANON_8600F) + move += settings.tl_y; + + int move_dpi = dev->motor.base_ydpi; + move = static_cast<float>((move * move_dpi) / MM_PER_INCH); + + float start = 0.0f; + if (settings.scan_method==ScanMethod::TRANSPARENCY || + settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) { - // FIXME: this is probably just an artifact of a bug elsewhere - start /= ccd_size_divisor; + start = dev->model->x_offset_ta; + } else { + start = dev->model->x_offset; } + start = start + settings.tl_x; - start += static_cast<int>(settings.tl_x); - start = static_cast<int>((start * sensor.optical_res) / MM_PER_INCH); + start = static_cast<float>((start * settings.xres) / MM_PER_INCH); ScanSession session; session.params.xres = settings.xres; session.params.yres = settings.yres; - session.params.startx = start; // not used - session.params.starty = 0; // not used + session.params.startx = static_cast<unsigned>(start); + session.params.starty = static_cast<unsigned>(move); session.params.pixels = settings.pixels; session.params.requested_pixels = settings.requested_pixels; session.params.lines = settings.lines; @@ -1259,8 +1124,7 @@ ScanSession CommandSetGl843::calculate_scan_session(const Genesys_Device* dev, 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; - + session.params.flags = flags; compute_session(dev, session, sensor); return session; @@ -1352,8 +1216,6 @@ void CommandSetGl843::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); @@ -1363,194 +1225,6 @@ void CommandSetGl843::detect_document_end(Genesys_Device* dev) const } } -// enables or disables XPA slider motor -void gl843_set_xpa_motor_power(Genesys_Device* dev, Genesys_Register_Set& regs, bool set) -{ - DBG_HELPER(dbg); - uint8_t val; - - if (dev->model->model_id == ModelId::CANON_8400F) { - - if (set) { - val = dev->interface->read_register(0x6c); - val &= ~(REG_0x6C_GPIO16 | REG_0x6C_GPIO13); - if (dev->session.output_resolution >= 2400) { - val &= ~REG_0x6C_GPIO10; - } - dev->interface->write_register(0x6c, val); - - val = dev->interface->read_register(0xa9); - val |= REG_0xA9_GPO30; - val &= ~REG_0xA9_GPO29; - dev->interface->write_register(0xa9, val); - } else { - val = dev->interface->read_register(0x6c); - val |= REG_0x6C_GPIO16 | REG_0x6C_GPIO13; - dev->interface->write_register(0x6c, val); - - val = dev->interface->read_register(0xa9); - val &= ~REG_0xA9_GPO30; - val |= REG_0xA9_GPO29; - dev->interface->write_register(0xa9, val); - } - } else if (dev->model->model_id == ModelId::CANON_8600F) { - if (set) { - val = dev->interface->read_register(REG_0x6C); - val &= ~REG_0x6C_GPIO14; - if (dev->session.output_resolution >= 2400) { - val |= REG_0x6C_GPIO10; - } - dev->interface->write_register(REG_0x6C, val); - - val = dev->interface->read_register(REG_0xA6); - val |= REG_0xA6_GPIO17; - val &= ~REG_0xA6_GPIO23; - dev->interface->write_register(REG_0xA6, val); - } else { - val = dev->interface->read_register(REG_0x6C); - val |= REG_0x6C_GPIO14; - val &= ~REG_0x6C_GPIO10; - dev->interface->write_register(REG_0x6C, val); - - val = dev->interface->read_register(REG_0xA6); - val &= ~REG_0xA6_GPIO17; - val &= ~REG_0xA6_GPIO23; - dev->interface->write_register(REG_0xA6, val); - } - } else if (dev->model->model_id == ModelId::HP_SCANJET_G4050) { - if (set) { - // set MULTFILM et GPOADF - val = dev->interface->read_register(REG_0x6B); - val |=REG_0x6B_MULTFILM|REG_0x6B_GPOADF; - dev->interface->write_register(REG_0x6B, val); - - val = dev->interface->read_register(REG_0x6C); - val &= ~REG_0x6C_GPIO15; - dev->interface->write_register(REG_0x6C, val); - - /* Motor power ? No move at all without this one */ - val = dev->interface->read_register(REG_0xA6); - val |= REG_0xA6_GPIO20; - dev->interface->write_register(REG_0xA6, val); - - val = dev->interface->read_register(REG_0xA8); - val &= ~REG_0xA8_GPO27; - dev->interface->write_register(REG_0xA8, val); - - val = dev->interface->read_register(REG_0xA9); - val |= REG_0xA9_GPO32|REG_0xA9_GPO31; - dev->interface->write_register(REG_0xA9, val); - } else { - // unset GPOADF - val = dev->interface->read_register(REG_0x6B); - val &= ~REG_0x6B_GPOADF; - dev->interface->write_register(REG_0x6B, val); - - val = dev->interface->read_register(REG_0xA8); - val |= REG_0xA8_GPO27; - dev->interface->write_register(REG_0xA8, val); - - val = dev->interface->read_register(REG_0xA9); - val &= ~REG_0xA9_GPO31; - dev->interface->write_register(REG_0xA9, val); - } - } - regs.state.is_xpa_motor_on = set; -} - - -/** @brief light XPA lamp - * toggle gpios to switch off regular lamp and light on the - * XPA light - * @param dev device to set up - */ -static void gl843_set_xpa_lamp_power(Genesys_Device* dev, bool set) -{ - DBG_HELPER(dbg); - - struct LampSettings { - ModelId model_id; - ScanMethod scan_method; - GenesysRegisterSettingSet regs_on; - GenesysRegisterSettingSet regs_off; - }; - - // FIXME: BUG: we're not clearing the registers to the previous state when returning back when - // turning off the lamp - LampSettings settings[] = { - { ModelId::CANON_8400F, ScanMethod::TRANSPARENCY, { - { 0xa6, 0x34, 0xf4 }, - }, { - { 0xa6, 0x40, 0x70 }, - } - }, - { ModelId::CANON_8400F, ScanMethod::TRANSPARENCY_INFRARED, { - { 0x6c, 0x40, 0x40 }, - { 0xa6, 0x01, 0xff }, - }, { - { 0x6c, 0x00, 0x40 }, - { 0xa6, 0x00, 0xff }, - } - }, - { ModelId::CANON_8600F, ScanMethod::TRANSPARENCY, { - { 0xa6, 0x34, 0xf4 }, - { 0xa7, 0xe0, 0xe0 }, - }, { - { 0xa6, 0x40, 0x70 }, - } - }, - { ModelId::CANON_8600F, ScanMethod::TRANSPARENCY_INFRARED, { - { 0xa6, 0x00, 0xc0 }, - { 0xa7, 0xe0, 0xe0 }, - { 0x6c, 0x80, 0x80 }, - }, { - { 0xa6, 0x00, 0xc0 }, - { 0x6c, 0x00, 0x80 }, - } - }, - { ModelId::PLUSTEK_OPTICFILM_7200I, ScanMethod::TRANSPARENCY, { - }, { - { 0xa6, 0x40, 0x70 }, // BUG: remove this cleanup write, it was enabled by accident - } - }, - { ModelId::PLUSTEK_OPTICFILM_7200I, ScanMethod::TRANSPARENCY_INFRARED, { - { 0xa8, 0x07, 0x07 }, - }, { - { 0xa8, 0x00, 0x07 }, - } - }, - { ModelId::PLUSTEK_OPTICFILM_7300, ScanMethod::TRANSPARENCY, {}, {} }, - { ModelId::PLUSTEK_OPTICFILM_7500I, ScanMethod::TRANSPARENCY, {}, {} }, - { ModelId::PLUSTEK_OPTICFILM_7500I, ScanMethod::TRANSPARENCY_INFRARED, { - { 0xa8, 0x07, 0x07 }, - }, { - { 0xa8, 0x00, 0x07 }, - } - }, - }; - - for (const auto& setting : settings) { - if (setting.model_id == dev->model->model_id && - setting.scan_method == dev->settings.scan_method) - { - apply_reg_settings_to_device(*dev, set ? setting.regs_on : setting.regs_off); - return; - } - } - - // BUG: we're currently calling the function in shut down path of regular lamp - if (set) { - throw SaneException("Unexpected code path entered"); - } - - GenesysRegisterSettingSet regs = { - { 0xa6, 0x40, 0x70 }, - }; - apply_reg_settings_to_device(*dev, regs); - // TODO: throw exception when we're only calling this function in error return path - // throw SaneException("Could not find XPA lamp settings"); -} - // Send the low-level scan command void CommandSetGl843::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, Genesys_Register_Set* reg, bool start_motor) const @@ -1580,30 +1254,44 @@ void CommandSetGl843::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens } if (reg->state.is_xpa_on && reg->state.is_lamp_on) { - gl843_set_xpa_lamp_power(dev, true); + dev->cmd_set->set_xpa_lamp_power(*dev, true); } if (reg->state.is_xpa_on) { - gl843_set_xpa_motor_power(dev, *reg, true); + dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY); } // blinking led dev->interface->write_register(REG_0x7E, 0x01); break; case GpioId::CANON_8400F: + if (dev->session.params.xres == 3200) + { + GenesysRegisterSettingSet reg_settings = { + { 0x6c, 0x00, 0x02 }, + }; + apply_reg_settings_to_device(*dev, reg_settings); + } + if (reg->state.is_xpa_on && reg->state.is_lamp_on) { + dev->cmd_set->set_xpa_lamp_power(*dev, true); + } + if (reg->state.is_xpa_on) { + dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY); + } + break; case GpioId::CANON_8600F: if (reg->state.is_xpa_on && reg->state.is_lamp_on) { - gl843_set_xpa_lamp_power(dev, true); + dev->cmd_set->set_xpa_lamp_power(*dev, true); } if (reg->state.is_xpa_on) { - gl843_set_xpa_motor_power(dev, *reg, true); + dev->cmd_set->set_motor_mode(*dev, *reg, MotorMode::PRIMARY_AND_SECONDARY); } break; case GpioId::PLUSTEK_OPTICFILM_7200I: case GpioId::PLUSTEK_OPTICFILM_7300: case GpioId::PLUSTEK_OPTICFILM_7500I: { if (reg->state.is_xpa_on && reg->state.is_lamp_on) { - gl843_set_xpa_lamp_power(dev, true); + dev->cmd_set->set_xpa_lamp_power(*dev, true); } break; } @@ -1612,8 +1300,7 @@ void CommandSetGl843::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens break; } - // clear scan and feed count - dev->interface->write_register(REG_0x0D, REG_0x0D_CLRLNCNT | REG_0x0D_CLRMCNT); + scanner_clear_scan_and_feed_counts(*dev); // enable scan and motor uint8_t val = dev->interface->read_register(REG_0x01); @@ -1622,11 +1309,26 @@ void CommandSetGl843::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sens scanner_start_action(*dev, start_motor); - if (reg->state.is_motor_on) { - dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); - } - if (reg->state.is_xpa_motor_on) { - dev->advance_head_pos_by_session(ScanHeadId::SECONDARY); + switch (reg->state.motor_mode) { + case MotorMode::PRIMARY: { + if (reg->state.is_motor_on) { + dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); + } + break; + } + case MotorMode::PRIMARY_AND_SECONDARY: { + if (reg->state.is_motor_on) { + dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); + dev->advance_head_pos_by_session(ScanHeadId::SECONDARY); + } + break; + } + case MotorMode::SECONDARY: { + if (reg->state.is_motor_on) { + dev->advance_head_pos_by_session(ScanHeadId::SECONDARY); + } + break; + } } } @@ -1640,10 +1342,8 @@ void CommandSetGl843::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg, // post scan gpio dev->interface->write_register(0x7e, 0x00); - // turn off XPA lamp if needed - // BUG: the if condition below probably shouldn't be enabled when XPA is off - if (reg->state.is_xpa_on || reg->state.is_lamp_on) { - gl843_set_xpa_lamp_power(dev, false); + if (reg->state.is_xpa_on) { + dev->cmd_set->set_xpa_lamp_power(*dev, false); } if (!dev->model->is_sheetfed) { @@ -1658,202 +1358,79 @@ void CommandSetGl843::move_back_home(Genesys_Device* dev, bool wait_until_home) 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 CommandSetGl843::search_start_position(Genesys_Device* dev) const -{ - DBG_HELPER(dbg); - 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 */ - - // 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); - - ScanSession session; - session.params.xres = dpi; - session.params.yres = dpi; - 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.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::GRAY; - session.params.color_filter = ColorFilter::GREEN; - 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); - - dev->cmd_set->begin_scan(dev, sensor, &local_reg, true); - - if (is_testing_mode()) { - dev->interface->test_checkpoint("search_start_position"); - end_scan(dev, &local_reg, true); - dev->reg = local_reg; - return; - } - - wait_until_buffer_non_empty(dev); - - // now we're on target, we can read data - Image image = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes_raw); - - scanner_stop_action_no_move(*dev, local_reg); - - if (DBG_LEVEL >= DBG_data) { - sanei_genesys_write_pnm_file("gl843_search_position.pnm", image); - } - - dev->cmd_set->end_scan(dev, &local_reg, true); - - /* update regs to copy ASIC internal state */ - dev->reg = local_reg; - - for (auto& sensor_update : - sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method)) - { - sanei_genesys_search_reference_point(dev, sensor_update, image.get_row_ptr(0), 0, dpi, - pixels, dev->model->search_lines); - } -} - -// sets up register for coarse gain calibration -// todo: check it for scanners using it -void CommandSetGl843::init_regs_for_coarse_calibration(Genesys_Device* dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) const -{ - DBG_HELPER(dbg); - - ScanFlag flags = ScanFlag::DISABLE_SHADING | - ScanFlag::DISABLE_GAMMA | - ScanFlag::SINGLE_LINE | - ScanFlag::IGNORE_LINE_DISTANCE; - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || - dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) { - flags |= ScanFlag::USE_XPA; - } - - ScanSession session; - session.params.xres = dev->settings.xres; - 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.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, ®s, session); - - sanei_genesys_set_motor_power(regs, false); - - 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->interface->write_registers(regs); -} - // init registers for shading calibration shading calibration is done at dpihw void CommandSetGl843::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, Genesys_Register_Set& regs) const { DBG_HELPER(dbg); - int move, resolution, dpihw, factor; - - /* initial calibration reg values */ - regs = dev->reg; - - dev->calib_channels = 3; + int move; + float calib_size_mm = 0; if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) { - dev->calib_lines = dev->model->shading_ta_lines; + calib_size_mm = dev->model->y_size_calib_ta_mm; } else { - dev->calib_lines = dev->model->shading_lines; + calib_size_mm = dev->model->y_size_calib_mm; } - dpihw = sensor.get_logical_hwdpi(dev->settings.xres); - factor=sensor.optical_res/dpihw; - resolution=dpihw; + unsigned resolution = sensor.shading_resolution; - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, dev->calib_channels, + unsigned channels = 3; + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, dev->settings.scan_method); - if ((dev->settings.scan_method == ScanMethod::TRANSPARENCY || - dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) && - dev->model->model_id == ModelId::CANON_8600F && - dev->settings.xres == 4800) - { - float offset = static_cast<float>(dev->model->x_offset_ta); - offset /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); - offset = static_cast<float>((offset * calib_sensor.optical_res) / MM_PER_INCH); + unsigned calib_pixels = 0; + unsigned calib_pixels_offset = 0; - float size = static_cast<float>(dev->model->x_size_ta); - size /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); - size = static_cast<float>((size * calib_sensor.optical_res) / MM_PER_INCH); + if (should_calibrate_only_active_area(*dev, dev->settings)) { + float offset = dev->model->x_offset_ta; + // FIXME: we should use resolution here + offset = static_cast<float>((offset * dev->settings.xres) / MM_PER_INCH); - dev->calib_pixels_offset = static_cast<std::size_t>(offset); - dev->calib_pixels = static_cast<std::size_t>(size); - } - else - { - dev->calib_pixels_offset = 0; - dev->calib_pixels = calib_sensor.sensor_pixels / factor; - } + float size = dev->model->x_size_ta; + size = static_cast<float>((size * dev->settings.xres) / MM_PER_INCH); - dev->calib_resolution = resolution; + calib_pixels_offset = static_cast<std::size_t>(offset); + calib_pixels = static_cast<std::size_t>(size); + } else { + calib_pixels_offset = 0; + calib_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH; + } ScanFlag flags = ScanFlag::DISABLE_SHADING | ScanFlag::DISABLE_GAMMA | - ScanFlag::DISABLE_BUFFER_FULL_MOVE | - ScanFlag::IGNORE_LINE_DISTANCE; + ScanFlag::DISABLE_BUFFER_FULL_MOVE; if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) { - // note: move_to_ta() function has already been called and the sensor is at the + // note: scanner_move_to_ta() function has already been called and the sensor is at the // transparency adapter move = static_cast<int>(dev->model->y_offset_calib_white_ta - dev->model->y_offset_sensor_to_ta); + if (dev->model->model_id == ModelId::CANON_8600F && resolution == 2400) { + move /= 2; + } + if (dev->model->model_id == ModelId::CANON_8600F && resolution == 4800) { + move /= 4; + } flags |= ScanFlag::USE_XPA; } else { move = static_cast<int>(dev->model->y_offset_calib_white); } move = static_cast<int>((move * resolution) / MM_PER_INCH); + unsigned calib_lines = static_cast<unsigned>(calib_size_mm * resolution / MM_PER_INCH); ScanSession session; session.params.xres = resolution; session.params.yres = resolution; - session.params.startx = dev->calib_pixels_offset; + session.params.startx = calib_pixels_offset; session.params.starty = move; - session.params.pixels = dev->calib_pixels; - session.params.lines = dev->calib_lines; + session.params.pixels = calib_pixels; + session.params.lines = calib_lines; session.params.depth = 16; - session.params.channels = dev->calib_channels; + session.params.channels = 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; @@ -1862,89 +1439,7 @@ void CommandSetGl843::init_regs_for_shading(Genesys_Device* dev, const Genesys_S init_regs_for_scan_session(dev, calib_sensor, ®s, session); - // the pixel number may be updated to conform to scanner constraints - dev->calib_pixels = session.output_pixels; - dev->calib_session = session; - dev->calib_total_bytes_to_read = session.output_total_bytes_raw; - - dev->interface->write_registers(regs); -} - -/** @brief set up registers for the actual scan - */ -void CommandSetGl843::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); - - move_dpi = dev->motor.base_ydpi; - - ScanFlag flags = ScanFlag::NONE; - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || - dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) - { - // note: move_to_ta() function has already been called and the sensor is at the - // transparency adapter - if (dev->ignore_offsets) { - move = 0; - } else { - move = static_cast<float>(dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta); - } - flags |= ScanFlag::USE_XPA; - } else { - if (dev->ignore_offsets) { - move = 0; - } else { - move = static_cast<float>(dev->model->y_offset); - } - } - - move += static_cast<float>(dev->settings.tl_y); - move = static_cast<float>((move * move_dpi) / MM_PER_INCH); - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - /* start */ - if (dev->settings.scan_method==ScanMethod::TRANSPARENCY || - dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) - { - start = static_cast<float>(dev->model->x_offset_ta); - } else { - start = static_cast<float>(dev->model->x_offset); - } - - if (dev->model->model_id == ModelId::CANON_8400F || - dev->model->model_id == ModelId::CANON_8600F) - { - // FIXME: this is probably just an artifact of a bug elsewhere - start /= sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres); - } - - start = static_cast<float>(start + dev->settings.tl_x); - start = static_cast<float>((start * sensor.optical_res) / MM_PER_INCH); - - ScanSession session; - session.params.xres = dev->settings.xres; - session.params.yres = dev->settings.yres; - session.params.startx = static_cast<unsigned>(start); - session.params.starty = static_cast<unsigned>(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); } /** @@ -1975,8 +1470,7 @@ void CommandSetGl843::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor gamma[i * 2 + size * 4 + 1] = (bgamma[i] >> 8) & 0xff; } - dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3, - ScannerInterface::FLAG_SWAP_REGISTERS); + dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3); } /* this function does the led calibration by scanning one line of the calibration @@ -1987,607 +1481,69 @@ void CommandSetGl843::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor SensorExposure CommandSetGl843::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, Genesys_Register_Set& regs) const { - DBG_HELPER(dbg); - int num_pixels; - int avg[3], avga, avge; - int turn; - uint16_t expr, expg, expb; - - // offset calibration is always done in color mode - unsigned channels = 3; - - // take a copy, as we're going to modify exposure - auto calib_sensor = sanei_genesys_find_sensor(dev, sensor.optical_res, channels, - dev->settings.scan_method); - - num_pixels = (calib_sensor.sensor_pixels * calib_sensor.optical_res) / calib_sensor.optical_res; - - /* initial calibration reg values */ - regs = dev->reg; - - ScanSession session; - session.params.xres = calib_sensor.sensor_pixels; - session.params.yres = dev->motor.base_ydpi; - 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); - - init_regs_for_scan_session(dev, calib_sensor, ®s, session); - - dev->interface->write_registers(regs); - -/* - we try to get equal bright leds here: - - loop: - average per color - adjust exposure times - */ - - expr = calib_sensor.exposure.red; - expg = calib_sensor.exposure.green; - expb = calib_sensor.exposure.blue; - - turn = 0; - - bool acceptable = false; - do - { - - calib_sensor.exposure.red = expr; - calib_sensor.exposure.green = expg; - calib_sensor.exposure.blue = expb; - - regs_set_exposure(dev->model->asic_type, regs, calib_sensor.exposure); - - dev->interface->write_registers(regs); - - DBG(DBG_info, "%s: starting first 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; - } - - auto image = read_unshuffled_image_from_scanner(dev, session, - session.output_total_bytes_raw); - scanner_stop_action_no_move(*dev, regs); - - if (DBG_LEVEL >= DBG_data) - { - char fn[30]; - std::snprintf(fn, 30, "gl843_led_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, image); - } - - acceptable = true; - - for (unsigned ch = 0; ch < channels; ch++) { - avg[ch] = 0; - for (std::size_t x = 0; x < image.get_width(); x++) { - avg[ch] += image.get_raw_channel(x, 0, ch); - } - avg[ch] /= image.get_width(); - } - - DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); - - acceptable = true; - - 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; - - if (!acceptable) - { - avga = (avg[0] + avg[1] + avg[2]) / 3; - expr = (expr * avga) / avg[0]; - expg = (expg * avga) / avg[1]; - expb = (expb * 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 = (expr + expg + expb) / 3; - - /* don't overflow max exposure */ - if (avge > 3000) - { - expr = (expr * 2000) / avge; - expg = (expg * 2000) / avge; - expb = (expb * 2000) / avge; - } - if (avge < 50) - { - expr = (expr * 50) / avge; - expg = (expg * 50) / avge; - expb = (expb * 50) / avge; - } - - } - scanner_stop_action(*dev); - - turn++; - - } - while (!acceptable && turn < 100); - - DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, expr, expg, expb); - - move_back_home(dev, true); - - return calib_sensor.exposure; -} - - - -/** - * average dark pixels of a 8 bits scan of a given channel - */ -static int dark_average_channel(const Image& image, unsigned black, unsigned channel) -{ - auto channels = get_pixel_channels(image.get_format()); - - unsigned avg[3]; - - // computes average values on black margin - for (unsigned ch = 0; ch < channels; ch++) { - avg[ch] = 0; - unsigned count = 0; - // FIXME: start with the second line because the black pixels often have noise on the first - // line; the cause is probably incorrectly cleaned up previous scan - for (std::size_t y = 1; y < image.get_height(); y++) { - for (unsigned j = 0; j < black; j++) { - avg[ch] += image.get_raw_channel(j, y, ch); - count++; - } - } - if (count > 0) { - avg[ch] /= count; - } - DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, ch, avg[ch]); - } - DBG(DBG_info, "%s: average = %d\n", __func__, avg[channel]); - return avg[channel]; + return scanner_led_calibration(*dev, sensor, regs); } -/** @brief calibrate AFE offset - * Iterate doing scans at target dpi until AFE offset if correct. One - * color line is scanned at a time. Scanning head doesn't move. - * @param dev device to calibrate - */ void CommandSetGl843::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, Genesys_Register_Set& regs) const { - DBG_HELPER(dbg); - - if (dev->frontend.layout.type != FrontendType::WOLFSON) - return; - - unsigned channels; - int pass, resolution, lines; - int topavg[3], bottomavg[3], avg[3]; - int top[3], bottom[3], black_pixels, pixels, factor, dpihw; - - /* offset calibration is always done in color mode */ - channels = 3; - lines = 8; - - // compute divider factor to compute final pixels number - dpihw = sensor.get_logical_hwdpi(dev->settings.xres); - factor = sensor.optical_res / dpihw; - resolution = dpihw; - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, - dev->settings.scan_method); - - int target_pixels = calib_sensor.sensor_pixels / factor; - int start_pixel = 0; - black_pixels = calib_sensor.black_pixels / factor; - - if ((dev->settings.scan_method == ScanMethod::TRANSPARENCY || - dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) && - dev->model->model_id == ModelId::CANON_8600F && - dev->settings.xres == 4800) - { - start_pixel = static_cast<int>(dev->model->x_offset_ta); - start_pixel /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); - start_pixel = static_cast<int>((start_pixel * calib_sensor.optical_res) / MM_PER_INCH); - - target_pixels = static_cast<int>(dev->model->x_size_ta); - target_pixels /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); - target_pixels = static_cast<int>((target_pixels * calib_sensor.optical_res) / MM_PER_INCH); - } - - ScanFlag flags = ScanFlag::DISABLE_SHADING | - ScanFlag::DISABLE_GAMMA | - ScanFlag::SINGLE_LINE | - ScanFlag::IGNORE_LINE_DISTANCE; - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || - dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) - { - flags |= ScanFlag::USE_XPA; - } - - ScanSession session; - session.params.xres = resolution; - session.params.yres = resolution; - session.params.startx = start_pixel; - session.params.starty = 0; - session.params.pixels = target_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::COLOR_SINGLE_PASS; - session.params.color_filter = ColorFilter::RED; - session.params.flags = flags; - compute_session(dev, session, calib_sensor); - pixels = session.output_pixels; - - DBG(DBG_io, "%s: dpihw =%d\n", __func__, dpihw); - DBG(DBG_io, "%s: factor =%d\n", __func__, factor); - DBG(DBG_io, "%s: resolution =%d\n", __func__, resolution); - DBG(DBG_io, "%s: pixels =%d\n", __func__, pixels); - DBG(DBG_io, "%s: black_pixels=%d\n", __func__, black_pixels); - init_regs_for_scan_session(dev, calib_sensor, ®s, session); - - sanei_genesys_set_motor_power(regs, false); - - // init gain and offset - for (unsigned ch = 0; ch < 3; ch++) - { - bottom[ch] = 10; - dev->frontend.set_offset(ch, bottom[ch]); - dev->frontend.set_gain(ch, 0); - } - dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); - - // scan with bottom AFE settings - dev->interface->write_registers(regs); - DBG(DBG_info, "%s: starting first line reading\n", __func__); - - dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); - - if (is_testing_mode()) { - dev->interface->test_checkpoint("offset_calibration"); - scanner_stop_action_no_move(*dev, regs); - return; - } - - auto first_line = read_unshuffled_image_from_scanner(dev, session, - session.output_total_bytes_raw); - scanner_stop_action_no_move(*dev, regs); - - if (DBG_LEVEL >= DBG_data) - { - char fn[40]; - std::snprintf(fn, 40, "gl843_bottom_offset_%03d_%03d_%03d.pnm", - bottom[0], bottom[1], bottom[2]); - sanei_genesys_write_pnm_file(fn, first_line); - } - - for (unsigned ch = 0; ch < 3; ch++) { - bottomavg[ch] = dark_average_channel(first_line, black_pixels, ch); - DBG(DBG_io2, "%s: bottom avg %d=%d\n", __func__, ch, bottomavg[ch]); - } - - // now top value - for (unsigned ch = 0; ch < 3; ch++) { - top[ch] = 255; - dev->frontend.set_offset(ch, top[ch]); - } - dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); - - // scan with top AFE values - dev->interface->write_registers(regs); - DBG(DBG_info, "%s: starting second line reading\n", __func__); - - dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); - auto second_line = read_unshuffled_image_from_scanner(dev, session, - session.output_total_bytes_raw); - scanner_stop_action_no_move(*dev, regs); - - for (unsigned ch = 0; ch < 3; ch++){ - topavg[ch] = dark_average_channel(second_line, black_pixels, ch); - DBG(DBG_io2, "%s: top avg %d=%d\n", __func__, ch, topavg[ch]); - } - - pass = 0; - - std::vector<uint8_t> debug_image; - size_t debug_image_lines = 0; - std::string debug_image_info; - - /* loop until acceptable level */ - while ((pass < 32) - && ((top[0] - bottom[0] > 1) - || (top[1] - bottom[1] > 1) || (top[2] - bottom[2] > 1))) - { - pass++; - - // settings for new scan - for (unsigned ch = 0; ch < 3; ch++) { - if (top[ch] - bottom[ch] > 1) { - dev->frontend.set_offset(ch, (top[ch] + bottom[ch]) / 2); - } - } - dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); - - // scan with no move - dev->interface->write_registers(regs); - DBG(DBG_info, "%s: starting second line reading\n", __func__); - dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); - second_line = read_unshuffled_image_from_scanner(dev, session, - session.output_total_bytes_raw); - scanner_stop_action_no_move(*dev, regs); - - if (DBG_LEVEL >= DBG_data) - { - char title[100]; - std::snprintf(title, 100, "lines: %d pixels_per_line: %d offsets[0..2]: %d %d %d\n", - lines, pixels, - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); - debug_image_info += title; - std::copy(second_line.get_row_ptr(0), - second_line.get_row_ptr(0) + second_line.get_row_bytes() * second_line.get_height(), - std::back_inserter(debug_image)); - debug_image_lines += lines; - } - - for (unsigned ch = 0; ch < 3; ch++) { - avg[ch] = dark_average_channel(second_line, black_pixels, ch); - DBG(DBG_info, "%s: avg[%d]=%d offset=%d\n", __func__, ch, avg[ch], - dev->frontend.get_offset(ch)); - } - - // compute new boundaries - for (unsigned ch = 0; ch < 3; ch++) { - if (topavg[ch] >= avg[ch]) { - topavg[ch] = avg[ch]; - top[ch] = dev->frontend.get_offset(ch); - } else { - bottomavg[ch] = avg[ch]; - bottom[ch] = dev->frontend.get_offset(ch); - } - } - } - - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_file("gl843_offset_all_desc.txt", - reinterpret_cast<const std::uint8_t*>(debug_image_info.data()), - debug_image_info.size()); - sanei_genesys_write_pnm_file("gl843_offset_all.pnm", - debug_image.data(), session.params.depth, channels, pixels, - debug_image_lines); - } - - DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); + scanner_offset_calibration(*dev, sensor, regs); } - -/* alternative coarse gain calibration - this on uses the settings from offset_calibration and - uses only one scanline - */ -/* - with offset and coarse calibration we only want to get our input range into - a reasonable shape. the fine calibration of the upper and lower bounds will - be done with shading. - */ void CommandSetGl843::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 factor, dpihw; - float coeff; - int lines; - int resolution; - - if (dev->frontend.layout.type != FrontendType::WOLFSON) - return; + scanner_coarse_gain_calibration(*dev, sensor, regs, dpi); +} - dpihw = sensor.get_logical_hwdpi(dpi); - factor=sensor.optical_res/dpihw; +// wait for lamp warmup by scanning the same line until difference +// between 2 scans is below a threshold +void CommandSetGl843::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg) const +{ + DBG_HELPER(dbg); + (void) sensor; - // coarse gain calibration is always done in color mode unsigned channels = 3; + unsigned resolution = dev->model->get_resolution_settings(dev->settings.scan_method) + .get_nearest_resolution_x(600); - /* follow CKSEL */ - if (dev->model->sensor_id == SensorId::CCD_KVSS080) { - if(dev->settings.xres<sensor.optical_res) - { - coeff = 0.9f; - } - else - { - coeff=1.0; - } - } - else - { - coeff=1.0; - } - resolution=dpihw; - lines=10; - int target_pixels = sensor.sensor_pixels / factor; + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, + dev->settings.scan_method); + unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH / 2; - ScanFlag flags = ScanFlag::DISABLE_SHADING | - ScanFlag::DISABLE_GAMMA | - ScanFlag::SINGLE_LINE | - ScanFlag::IGNORE_LINE_DISTANCE; + *reg = dev->reg; + 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; } - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, - dev->settings.scan_method); - ScanSession session; session.params.xres = resolution; session.params.yres = resolution; - session.params.startx = 0; + session.params.startx = (num_pixels / 2) * resolution / calib_sensor.full_resolution; session.params.starty = 0; - session.params.pixels = target_pixels; - session.params.lines = lines; - session.params.depth = 8; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = dev->model->bpp_color_values.front(); 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 = flags; - compute_session(dev, session, calib_sensor); - std::size_t pixels = session.output_pixels; - - try { - init_regs_for_scan_session(dev, calib_sensor, ®s, session); - } catch (...) { - catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); }); - throw; - } - - sanei_genesys_set_motor_power(regs, false); - - dev->interface->write_registers(regs); - - dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); - dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); - - if (is_testing_mode()) { - dev->interface->test_checkpoint("coarse_gain_calibration"); - scanner_stop_action(*dev); - move_back_home(dev, true); - return; - } - - auto line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes_raw); - scanner_stop_action_no_move(*dev, regs); - - if (DBG_LEVEL >= DBG_data) { - sanei_genesys_write_pnm_file("gl843_gain.pnm", line); - } - - // average value on each channel - for (unsigned ch = 0; ch < channels; ch++) { - - std::vector<uint16_t> values; - // FIXME: start from the second line because the first line often has artifacts. Probably - // caused by unclean cleanup of previous scan - for (std::size_t x = pixels / 4; x < (pixels * 3 / 4); x++) { - values.push_back(line.get_raw_channel(x, 1, ch)); - } - // pick target value at 95th percentile of all values. There may be a lot of black values - // in transparency scans for example - std::sort(values.begin(), values.end()); - uint16_t curr_output = values[unsigned((values.size() - 1) * 0.95)]; - float target_value = calib_sensor.gain_white_ref * coeff; - - int code = compute_frontend_gain(curr_output, target_value, dev->frontend.layout.type); - dev->frontend.set_gain(ch, code); - - DBG(DBG_proc, "%s: channel %d, max=%d, target=%d, setting:%d\n", __func__, ch, curr_output, - static_cast<int>(target_value), code); - } - - 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)); - } - - scanner_stop_action(*dev); - - move_back_home(dev, true); -} - -// wait for lamp warmup by scanning the same line until difference -// between 2 scans is below a threshold -void CommandSetGl843::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set* reg, int* channels, - int* total_size) const -{ - DBG_HELPER(dbg); - int num_pixels; - int dpihw; - int resolution; - int factor; - - /* setup scan */ - *channels=3; - resolution=600; - dpihw = sensor.get_logical_hwdpi(resolution); - resolution=dpihw; - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, *channels, - dev->settings.scan_method); - factor = calib_sensor.optical_res/dpihw; - num_pixels = calib_sensor.sensor_pixels/(factor*2); - *total_size = num_pixels * 3 * 1; - - *reg = dev->reg; - - ScanSession session; - session.params.xres = resolution; - session.params.yres = resolution; - session.params.startx = num_pixels/2; - session.params.starty = 0; - session.params.pixels = num_pixels; - session.params.lines = 1; - session.params.depth = 8; - 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, reg, session); sanei_genesys_set_motor_power(*reg, false); - dev->interface->write_registers(*reg); } /** @@ -2654,7 +1610,7 @@ void CommandSetGl843::asic_boot(Genesys_Device* dev, bool cold) const val = dev->reg.find_reg(0x0b).value & REG_0x0B_DRAMSEL; val = (val | REG_0x0B_ENBDRAM); dev->interface->write_register(REG_0x0B, val); - dev->reg.find_reg(0x0b).value = val; + dev->reg.find_reg(0x0b).value = val; if (dev->model->model_id == ModelId::CANON_8400F) { dev->interface->write_0x8c(0x1e, 0x01); @@ -2691,18 +1647,11 @@ void CommandSetGl843::asic_boot(Genesys_Device* dev, bool cold) const val = (dev->reg.find_reg(0x0b).value & ~REG_0x0B_CLKSET) | clock_freq; dev->interface->write_register(REG_0x0B, val); - dev->reg.find_reg(0x0b).value = val; + dev->reg.find_reg(0x0b).value = val; /* prevent further writings by bulk write register */ dev->reg.remove_reg(0x0b); - if (dev->model->model_id != ModelId::CANON_8600F) { - // set up end access - // FIXME: this is overwritten in gl843_init_gpio - dev->interface->write_register(REG_0xA7, 0x04); - dev->interface->write_register(REG_0xA9, 0x00); - } - // set RAM read address dev->interface->write_register(REG_0x29, 0x00); dev->interface->write_register(REG_0x2A, 0x00); @@ -2710,8 +1659,6 @@ void CommandSetGl843::asic_boot(Genesys_Device* dev, bool cold) const // setup gpio gl843_init_gpio(dev); - - scanner_move(*dev, dev->model->default_method, 300, Direction::FORWARD); dev->interface->sleep_ms(100); } @@ -2724,7 +1671,7 @@ void CommandSetGl843::init(Genesys_Device* dev) const DBG_INIT (); DBG_HELPER(dbg); - sanei_genesys_asic_init(dev, 0); + sanei_genesys_asic_init(dev); } void CommandSetGl843::update_hardware_sensors(Genesys_Scanner* s) const @@ -2754,216 +1701,10 @@ void CommandSetGl843::update_hardware_sensors(Genesys_Scanner* s) const } } -/** @brief move sensor to transparency adaptor - * Move sensor to the calibration of the transparency adapator (XPA). - * @param dev device to use - */ -void CommandSetGl843::move_to_ta(Genesys_Device* dev) const +void CommandSetGl843::update_home_sensor_gpio(Genesys_Device& dev) const { DBG_HELPER(dbg); - - const auto& resolution_settings = dev->model->get_resolution_settings(dev->model->default_method); - float resolution = resolution_settings.get_min_resolution_y(); - - unsigned multiplier = 16; - if (dev->model->model_id == ModelId::CANON_8400F) { - multiplier = 4; - } - unsigned feed = static_cast<unsigned>(multiplier * (dev->model->y_offset_sensor_to_ta * resolution) / - MM_PER_INCH); - scanner_move(*dev, dev->model->default_method, feed, Direction::FORWARD); -} - - -/** @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 CommandSetGl843::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; - int dpi; - unsigned int pass, count, found, x, y; - - dev->cmd_set->set_fe(dev, sensor, AFE_SET); - scanner_stop_action(*dev); - - /* set up for a gray scan at lowest dpi */ - dpi = sanei_genesys_get_lowest_dpi(dev); - channels = 1; - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, dpi, channels, - dev->settings.scan_method); - - /* 10 MM */ - /* lines = (10 * dpi) / MM_PER_INCH; */ - /* shading calibation is done with dev->motor.base_ydpi */ - lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; - pixels = (calib_sensor.sensor_pixels * dpi) / calib_sensor.optical_res; - - 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_SHADING; - if (!forward) { - session.params.flags = ScanFlag::REVERSE; - } - compute_session(dev, session, calib_sensor); - - init_regs_for_scan_session(dev, calib_sensor, &local_reg, session); - - dev->interface->write_registers(local_reg); - - dev->cmd_set->begin_scan(dev, calib_sensor, &local_reg, true); - - if (is_testing_mode()) { - dev->interface->test_checkpoint("search_strip"); - scanner_stop_action(*dev); - return; - } - - wait_until_buffer_non_empty(dev); - - // now we're on target, we can read data - auto data = read_unshuffled_image_from_scanner(dev, session, - session.output_total_bytes_raw); - - scanner_stop_action(*dev); - - pass = 0; - if (DBG_LEVEL >= DBG_data) - { - char fn[40]; - std::snprintf(fn, 40, "gl843_search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", pass); - sanei_genesys_write_pnm_file(fn, data); - } - - /* loop until strip is found or maximum pass number done */ - found = 0; - while (pass < 20 && !found) - { - dev->interface->write_registers(local_reg); - - // now start scan - dev->cmd_set->begin_scan(dev, calib_sensor, &local_reg, true); - - wait_until_buffer_non_empty(dev); - - // now we're on target, we can read data - data = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes_raw); - - scanner_stop_action(*dev); - - if (DBG_LEVEL >= DBG_data) - { - char fn[40]; - std::snprintf(fn, 40, "gl843_search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", pass); - sanei_genesys_write_pnm_file(fn, data); - } - - /* 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.get_raw_channel(x, y, 0) > 90) { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data.get_raw_channel(x, y, 0) < 60) { - 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.get_raw_channel(x, y, 0) > 90) { - count++; - } - // when searching for white, detect black pixels - if (!black && data.get_raw_channel(x, y, 0) < 60) { - 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"); - } + (void) dev; } /** @@ -2974,43 +1715,27 @@ void CommandSetGl843::send_shading_data(Genesys_Device* dev, const Genesys_Senso uint8_t* data, int size) const { DBG_HELPER(dbg); - uint32_t final_size, length, i; + uint32_t final_size, i; uint8_t *buffer; - int count,offset; - GenesysRegister *r; - uint16_t strpixel, endpixel, startx; - - offset=0; - length=size; - r = sanei_genesys_get_address(&dev->reg, REG_0x01); - if (r->value & REG_0x01_SHDAREA) - { - /* recompute STRPIXEL used shading calibration so we can - * compute offset within data for SHDAREA case */ - - // FIXME: the following is likely incorrect - // start coordinate in optical dpi coordinates - startx = (sensor.dummy_pixel / sensor.ccd_pixels_per_system_pixel()) / dev->session.hwdpi_divisor; - startx *= dev->session.pixel_count_multiplier; - - /* current scan coordinates */ - strpixel = dev->session.pixel_startx; - endpixel = dev->session.pixel_endx; - - if (dev->model->model_id == ModelId::CANON_4400F || - dev->model->model_id == ModelId::CANON_8600F) - { - int half_ccd_factor = dev->session.optical_resolution / - sensor.get_logical_hwdpi(dev->session.output_resolution); - strpixel /= half_ccd_factor * sensor.ccd_pixels_per_system_pixel(); - endpixel /= half_ccd_factor * sensor.ccd_pixels_per_system_pixel(); - } + int count; + + int offset = 0; + unsigned length = size; + + if (dev->reg.get8(REG_0x01) & REG_0x01_SHDAREA) { + offset = dev->session.params.startx * sensor.shading_resolution / + dev->session.params.xres; - /* 16 bit words, 2 words per color, 3 color channels */ - offset=(strpixel-startx)*2*2*3; - length=(endpixel-strpixel)*2*2*3; - DBG(DBG_info, "%s: STRPIXEL=%d, ENDPIXEL=%d, startx=%d\n", __func__, strpixel, endpixel, - startx); + length = dev->session.output_pixels * sensor.shading_resolution / + dev->session.params.xres; + + offset += sensor.shading_pixel_offset; + + // 16 bit words, 2 words per color, 3 color channels + length *= 2 * 2 * 3; + offset *= 2 * 2 * 3; + } else { + offset += sensor.shading_pixel_offset * 2 * 2 * 3; } dev->interface->record_key_value("shading_offset", std::to_string(offset)); @@ -3024,6 +1749,14 @@ void CommandSetGl843::send_shading_data(Genesys_Device* dev, const Genesys_Senso /* copy regular shading data to the expected layout */ buffer = final_data.data(); count = 0; + if (offset < 0) { + count += (-offset); + length -= (-offset); + offset = 0; + } + if (static_cast<int>(length) + offset > static_cast<int>(size)) { + length = size - offset; + } /* loop over calibration data */ for (i = 0; i < length; i++) @@ -3036,8 +1769,7 @@ void CommandSetGl843::send_shading_data(Genesys_Device* dev, const Genesys_Senso } } - dev->interface->write_buffer(0x3c, 0, final_data.data(), count, - ScannerInterface::FLAG_SMALL_ADDRESS); + dev->interface->write_buffer(0x3c, 0, final_data.data(), count); } bool CommandSetGl843::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const @@ -3051,10 +1783,5 @@ void CommandSetGl843::wait_for_motor_stop(Genesys_Device* dev) const (void) dev; } -std::unique_ptr<CommandSet> create_gl843_cmd_set() -{ - return std::unique_ptr<CommandSet>(new CommandSetGl843{}); -} - } // namespace gl843 } // namespace genesys |