1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2003 Oliver Rauch 4141cc406Sopenharmony_ci Copyright (C) 2003, 2004 Henning Meier-Geinitz <henning@meier-geinitz.de> 5141cc406Sopenharmony_ci Copyright (C) 2004 Gerhard Jaeger <gerhard@gjaeger.de> 6141cc406Sopenharmony_ci Copyright (C) 2004-2013 Stéphane Voltz <stef.dev@free.fr> 7141cc406Sopenharmony_ci Copyright (C) 2005-2009 Pierre Willenbrock <pierre@pirsoft.dnsalias.org> 8141cc406Sopenharmony_ci Copyright (C) 2007 Luke <iceyfor@gmail.com> 9141cc406Sopenharmony_ci Copyright (C) 2011 Alexey Osipov <simba@lerlan.ru> for HP2400 description 10141cc406Sopenharmony_ci and tuning 11141cc406Sopenharmony_ci 12141cc406Sopenharmony_ci This file is part of the SANE package. 13141cc406Sopenharmony_ci 14141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 15141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 16141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 17141cc406Sopenharmony_ci License, or (at your option) any later version. 18141cc406Sopenharmony_ci 19141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 20141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 21141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22141cc406Sopenharmony_ci General Public License for more details. 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 25141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 26141cc406Sopenharmony_ci*/ 27141cc406Sopenharmony_ci 28141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 29141cc406Sopenharmony_ci 30141cc406Sopenharmony_ci#include "gl646.h" 31141cc406Sopenharmony_ci#include "gl646_registers.h" 32141cc406Sopenharmony_ci#include "test_settings.h" 33141cc406Sopenharmony_ci 34141cc406Sopenharmony_ci#include <vector> 35141cc406Sopenharmony_ci 36141cc406Sopenharmony_cinamespace genesys { 37141cc406Sopenharmony_cinamespace gl646 { 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_cinamespace { 40141cc406Sopenharmony_ciconstexpr unsigned CALIBRATION_LINES = 10; 41141cc406Sopenharmony_ci} // namespace 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_cistatic void write_control(Genesys_Device* dev, const Genesys_Sensor& sensor, int resolution); 44141cc406Sopenharmony_ci 45141cc406Sopenharmony_ci 46141cc406Sopenharmony_cistatic void gl646_set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, std::uint8_t set, 47141cc406Sopenharmony_ci int dpi); 48141cc406Sopenharmony_ci 49141cc406Sopenharmony_cistatic void simple_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, 50141cc406Sopenharmony_ci const ScanSession& session, bool move, 51141cc406Sopenharmony_ci std::vector<std::uint8_t>& data, const char* test_identifier); 52141cc406Sopenharmony_ci/** 53141cc406Sopenharmony_ci * Send the stop scan command 54141cc406Sopenharmony_ci * */ 55141cc406Sopenharmony_cistatic void end_scan_impl(Genesys_Device* dev, Genesys_Register_Set* reg, bool check_stop, 56141cc406Sopenharmony_ci bool eject); 57141cc406Sopenharmony_ci 58141cc406Sopenharmony_ci/** 59141cc406Sopenharmony_ci * master motor settings table entry 60141cc406Sopenharmony_ci */ 61141cc406Sopenharmony_cistruct Motor_Master 62141cc406Sopenharmony_ci{ 63141cc406Sopenharmony_ci MotorId motor_id; 64141cc406Sopenharmony_ci unsigned dpi; 65141cc406Sopenharmony_ci unsigned channels; 66141cc406Sopenharmony_ci 67141cc406Sopenharmony_ci // settings 68141cc406Sopenharmony_ci StepType steptype; 69141cc406Sopenharmony_ci bool fastmod; // fast scanning 70141cc406Sopenharmony_ci bool fastfed; // fast fed slope tables 71141cc406Sopenharmony_ci SANE_Int mtrpwm; 72141cc406Sopenharmony_ci MotorSlope slope1; 73141cc406Sopenharmony_ci MotorSlope slope2; 74141cc406Sopenharmony_ci SANE_Int fwdbwd; // forward/backward steps 75141cc406Sopenharmony_ci}; 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_ci/** 78141cc406Sopenharmony_ci * master motor settings, for a given motor and dpi, 79141cc406Sopenharmony_ci * it gives steps and speed information 80141cc406Sopenharmony_ci */ 81141cc406Sopenharmony_cistatic Motor_Master motor_master[] = { 82141cc406Sopenharmony_ci /* HP3670 motor settings */ 83141cc406Sopenharmony_ci {MotorId::HP3670, 50, 3, StepType::HALF, false, true, 1, 84141cc406Sopenharmony_ci MotorSlope::create_from_steps(2329, 120, 229), 85141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_ci {MotorId::HP3670, 75, 3, StepType::FULL, false, true, 1, 88141cc406Sopenharmony_ci MotorSlope::create_from_steps(3429, 305, 200), 89141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 90141cc406Sopenharmony_ci 91141cc406Sopenharmony_ci {MotorId::HP3670, 100, 3, StepType::HALF, false, true, 1, 92141cc406Sopenharmony_ci MotorSlope::create_from_steps(2905, 187, 143), 93141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 94141cc406Sopenharmony_ci 95141cc406Sopenharmony_ci {MotorId::HP3670, 150, 3, StepType::HALF, false, true, 1, 96141cc406Sopenharmony_ci MotorSlope::create_from_steps(3429, 305, 73), 97141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 98141cc406Sopenharmony_ci 99141cc406Sopenharmony_ci {MotorId::HP3670, 300, 3, StepType::HALF, false, true, 1, 100141cc406Sopenharmony_ci MotorSlope::create_from_steps(1055, 563, 11), 101141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 102141cc406Sopenharmony_ci 103141cc406Sopenharmony_ci {MotorId::HP3670, 600, 3, StepType::FULL, false, true, 0, 104141cc406Sopenharmony_ci MotorSlope::create_from_steps(10687, 5126, 3), 105141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 106141cc406Sopenharmony_ci 107141cc406Sopenharmony_ci {MotorId::HP3670,1200, 3, StepType::HALF, false, true, 0, 108141cc406Sopenharmony_ci MotorSlope::create_from_steps(15937, 6375, 3), 109141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 110141cc406Sopenharmony_ci 111141cc406Sopenharmony_ci {MotorId::HP3670, 50, 1, StepType::HALF, false, true, 1, 112141cc406Sopenharmony_ci MotorSlope::create_from_steps(2329, 120, 229), 113141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 114141cc406Sopenharmony_ci 115141cc406Sopenharmony_ci {MotorId::HP3670, 75, 1, StepType::FULL, false, true, 1, 116141cc406Sopenharmony_ci MotorSlope::create_from_steps(3429, 305, 200), 117141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 118141cc406Sopenharmony_ci 119141cc406Sopenharmony_ci {MotorId::HP3670, 100, 1, StepType::HALF, false, true, 1, 120141cc406Sopenharmony_ci MotorSlope::create_from_steps(2905, 187, 143), 121141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 122141cc406Sopenharmony_ci 123141cc406Sopenharmony_ci {MotorId::HP3670, 150, 1, StepType::HALF, false, true, 1, 124141cc406Sopenharmony_ci MotorSlope::create_from_steps(3429, 305, 73), 125141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 126141cc406Sopenharmony_ci 127141cc406Sopenharmony_ci {MotorId::HP3670, 300, 1, StepType::HALF, false, true, 1, 128141cc406Sopenharmony_ci MotorSlope::create_from_steps(1055, 563, 11), 129141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 130141cc406Sopenharmony_ci 131141cc406Sopenharmony_ci {MotorId::HP3670, 600, 1, StepType::FULL, false, true, 0, 132141cc406Sopenharmony_ci MotorSlope::create_from_steps(10687, 5126, 3), 133141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 134141cc406Sopenharmony_ci 135141cc406Sopenharmony_ci {MotorId::HP3670,1200, 1, StepType::HALF, false, true, 0, 136141cc406Sopenharmony_ci MotorSlope::create_from_steps(15937, 6375, 3), 137141cc406Sopenharmony_ci MotorSlope::create_from_steps(3399, 337, 192), 192}, 138141cc406Sopenharmony_ci 139141cc406Sopenharmony_ci /* HP2400/G2410 motor settings base motor dpi = 600 */ 140141cc406Sopenharmony_ci {MotorId::HP2400, 50, 3, StepType::FULL, false, true, 63, 141141cc406Sopenharmony_ci MotorSlope::create_from_steps(8736, 601, 120), 142141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 192), 192}, 143141cc406Sopenharmony_ci 144141cc406Sopenharmony_ci {MotorId::HP2400, 100, 3, StepType::HALF, false, true, 63, 145141cc406Sopenharmony_ci MotorSlope::create_from_steps(8736, 601, 120), 146141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 192), 192}, 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_ci {MotorId::HP2400, 150, 3, StepType::HALF, false, true, 63, 149141cc406Sopenharmony_ci MotorSlope::create_from_steps(15902, 902, 67), 150141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 192), 192}, 151141cc406Sopenharmony_ci 152141cc406Sopenharmony_ci {MotorId::HP2400, 300, 3, StepType::HALF, false, true, 63, 153141cc406Sopenharmony_ci MotorSlope::create_from_steps(16703, 2188, 32), 154141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 192), 192}, 155141cc406Sopenharmony_ci 156141cc406Sopenharmony_ci {MotorId::HP2400, 600, 3, StepType::FULL, false, true, 63, 157141cc406Sopenharmony_ci MotorSlope::create_from_steps(18761, 18761, 3), 158141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 627, 192), 192}, 159141cc406Sopenharmony_ci 160141cc406Sopenharmony_ci {MotorId::HP2400,1200, 3, StepType::HALF, false, true, 63, 161141cc406Sopenharmony_ci MotorSlope::create_from_steps(43501, 43501, 3), 162141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 627, 192), 192}, 163141cc406Sopenharmony_ci 164141cc406Sopenharmony_ci {MotorId::HP2400, 50, 1, StepType::FULL, false, true, 63, 165141cc406Sopenharmony_ci MotorSlope::create_from_steps(8736, 601, 120), 166141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 192), 192}, 167141cc406Sopenharmony_ci 168141cc406Sopenharmony_ci {MotorId::HP2400, 100, 1, StepType::HALF, false, true, 63, 169141cc406Sopenharmony_ci MotorSlope::create_from_steps(8736, 601, 120), 170141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 192), 192}, 171141cc406Sopenharmony_ci 172141cc406Sopenharmony_ci {MotorId::HP2400, 150, 1, StepType::HALF, false, true, 63, 173141cc406Sopenharmony_ci MotorSlope::create_from_steps(15902, 902, 67), 174141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 192), 192}, 175141cc406Sopenharmony_ci 176141cc406Sopenharmony_ci {MotorId::HP2400, 300, 1, StepType::HALF, false, true, 63, 177141cc406Sopenharmony_ci MotorSlope::create_from_steps(16703, 2188, 32), 178141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 192), 192}, 179141cc406Sopenharmony_ci 180141cc406Sopenharmony_ci {MotorId::HP2400, 600, 1, StepType::FULL, false, true, 63, 181141cc406Sopenharmony_ci MotorSlope::create_from_steps(18761, 18761, 3), 182141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 192), 192}, 183141cc406Sopenharmony_ci 184141cc406Sopenharmony_ci {MotorId::HP2400,1200, 1, StepType::HALF, false, true, 63, 185141cc406Sopenharmony_ci MotorSlope::create_from_steps(43501, 43501, 3), 186141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 192), 192}, 187141cc406Sopenharmony_ci 188141cc406Sopenharmony_ci /* XP 200 motor settings */ 189141cc406Sopenharmony_ci {MotorId::XP200, 75, 3, StepType::HALF, true, false, 0, 190141cc406Sopenharmony_ci MotorSlope::create_from_steps(6000, 2136, 4), 191141cc406Sopenharmony_ci MotorSlope::create_from_steps(12000, 1200, 8), 1}, 192141cc406Sopenharmony_ci 193141cc406Sopenharmony_ci {MotorId::XP200, 100, 3, StepType::HALF, true, false, 0, 194141cc406Sopenharmony_ci MotorSlope::create_from_steps(6000, 2850, 4), 195141cc406Sopenharmony_ci MotorSlope::create_from_steps(12000, 1200, 8), 1}, 196141cc406Sopenharmony_ci 197141cc406Sopenharmony_ci {MotorId::XP200, 200, 3, StepType::HALF, true, false, 0, 198141cc406Sopenharmony_ci MotorSlope::create_from_steps(6999, 5700, 4), 199141cc406Sopenharmony_ci MotorSlope::create_from_steps(12000, 1200, 8), 1}, 200141cc406Sopenharmony_ci 201141cc406Sopenharmony_ci {MotorId::XP200, 250, 3, StepType::HALF, true, false, 0, 202141cc406Sopenharmony_ci MotorSlope::create_from_steps(6999, 6999, 4), 203141cc406Sopenharmony_ci MotorSlope::create_from_steps(12000, 1200, 8), 1}, 204141cc406Sopenharmony_ci 205141cc406Sopenharmony_ci {MotorId::XP200, 300, 3, StepType::HALF, true, false, 0, 206141cc406Sopenharmony_ci MotorSlope::create_from_steps(13500, 13500, 4), 207141cc406Sopenharmony_ci MotorSlope::create_from_steps(12000, 1200, 8), 1}, 208141cc406Sopenharmony_ci 209141cc406Sopenharmony_ci {MotorId::XP200, 600, 3, StepType::HALF, true, true, 0, 210141cc406Sopenharmony_ci MotorSlope::create_from_steps(31998, 31998, 4), 211141cc406Sopenharmony_ci MotorSlope::create_from_steps(12000, 1200, 2), 1}, 212141cc406Sopenharmony_ci 213141cc406Sopenharmony_ci {MotorId::XP200, 75, 1, StepType::HALF, true, false, 0, 214141cc406Sopenharmony_ci MotorSlope::create_from_steps(6000, 2000, 4), 215141cc406Sopenharmony_ci MotorSlope::create_from_steps(12000, 1200, 8), 1}, 216141cc406Sopenharmony_ci 217141cc406Sopenharmony_ci {MotorId::XP200, 100, 1, StepType::HALF, true, false, 0, 218141cc406Sopenharmony_ci MotorSlope::create_from_steps(6000, 1300, 4), 219141cc406Sopenharmony_ci MotorSlope::create_from_steps(12000, 1200, 8), 1}, 220141cc406Sopenharmony_ci 221141cc406Sopenharmony_ci {MotorId::XP200, 200, 1, StepType::HALF, true, true, 0, 222141cc406Sopenharmony_ci MotorSlope::create_from_steps(6000, 3666, 4), 223141cc406Sopenharmony_ci MotorSlope::create_from_steps(12000, 1200, 8), 1}, 224141cc406Sopenharmony_ci 225141cc406Sopenharmony_ci {MotorId::XP200, 300, 1, StepType::HALF, true, false, 0, 226141cc406Sopenharmony_ci MotorSlope::create_from_steps(6500, 6500, 4), 227141cc406Sopenharmony_ci MotorSlope::create_from_steps(12000, 1200, 8), 1}, 228141cc406Sopenharmony_ci 229141cc406Sopenharmony_ci {MotorId::XP200, 600, 1, StepType::HALF, true, true, 0, 230141cc406Sopenharmony_ci MotorSlope::create_from_steps(24000, 24000, 4), 231141cc406Sopenharmony_ci MotorSlope::create_from_steps(12000, 1200, 2), 1}, 232141cc406Sopenharmony_ci 233141cc406Sopenharmony_ci /* HP scanjet 2300c */ 234141cc406Sopenharmony_ci {MotorId::HP2300, 75, 3, StepType::FULL, false, true, 63, 235141cc406Sopenharmony_ci MotorSlope::create_from_steps(8139, 560, 120), 236141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 237141cc406Sopenharmony_ci 238141cc406Sopenharmony_ci {MotorId::HP2300, 150, 3, StepType::HALF, false, true, 63, 239141cc406Sopenharmony_ci MotorSlope::create_from_steps(7903, 543, 67), 240141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 241141cc406Sopenharmony_ci 242141cc406Sopenharmony_ci {MotorId::HP2300, 300, 3, StepType::HALF, false, true, 63, 243141cc406Sopenharmony_ci MotorSlope::create_from_steps(2175, 1087, 3), 244141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 245141cc406Sopenharmony_ci 246141cc406Sopenharmony_ci {MotorId::HP2300, 600, 3, StepType::HALF, false, true, 63, 247141cc406Sopenharmony_ci MotorSlope::create_from_steps(8700, 4350, 3), 248141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 249141cc406Sopenharmony_ci 250141cc406Sopenharmony_ci {MotorId::HP2300,1200, 3, StepType::HALF, false, true, 63, 251141cc406Sopenharmony_ci MotorSlope::create_from_steps(17400, 8700, 3), 252141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 253141cc406Sopenharmony_ci 254141cc406Sopenharmony_ci {MotorId::HP2300, 75, 1, StepType::FULL, false, true, 63, 255141cc406Sopenharmony_ci MotorSlope::create_from_steps(8139, 560, 120), 256141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 257141cc406Sopenharmony_ci 258141cc406Sopenharmony_ci {MotorId::HP2300, 150, 1, StepType::HALF, false, true, 63, 259141cc406Sopenharmony_ci MotorSlope::create_from_steps(7903, 543, 67), 260141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 261141cc406Sopenharmony_ci 262141cc406Sopenharmony_ci {MotorId::HP2300, 300, 1, StepType::HALF, false, true, 63, 263141cc406Sopenharmony_ci MotorSlope::create_from_steps(2175, 1087, 3), 264141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 265141cc406Sopenharmony_ci 266141cc406Sopenharmony_ci {MotorId::HP2300, 600, 1, StepType::HALF, false, true, 63, 267141cc406Sopenharmony_ci MotorSlope::create_from_steps(8700, 4350, 3), 268141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 269141cc406Sopenharmony_ci 270141cc406Sopenharmony_ci {MotorId::HP2300,1200, 1, StepType::HALF, false, true, 63, 271141cc406Sopenharmony_ci MotorSlope::create_from_steps(17400, 8700, 3), 272141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 273141cc406Sopenharmony_ci 274141cc406Sopenharmony_ci /* non half ccd settings for 300 dpi 275141cc406Sopenharmony_ci {MotorId::HP2300, 300, 3, StepType::HALF, false, true, 63, 276141cc406Sopenharmony_ci MotorSlope::create_from_steps(5386, 2175, 44), 277141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 278141cc406Sopenharmony_ci 279141cc406Sopenharmony_ci {MotorId::HP2300, 300, 1, StepType::HALF, false, true, 63, 280141cc406Sopenharmony_ci MotorSlope::create_from_steps(5386, 2175, 44), 281141cc406Sopenharmony_ci MotorSlope::create_from_steps(4905, 337, 120), 16}, 282141cc406Sopenharmony_ci */ 283141cc406Sopenharmony_ci 284141cc406Sopenharmony_ci /* MD5345/6471 motor settings */ 285141cc406Sopenharmony_ci /* vfinal=(exposure/(1200/dpi))/step_type */ 286141cc406Sopenharmony_ci {MotorId::MD_5345, 50, 3, StepType::HALF, false, true, 2, 287141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 250, 255), 288141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 289141cc406Sopenharmony_ci 290141cc406Sopenharmony_ci {MotorId::MD_5345, 75, 3, StepType::HALF, false, true, 2, 291141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 343, 255), 292141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 293141cc406Sopenharmony_ci 294141cc406Sopenharmony_ci {MotorId::MD_5345, 100, 3, StepType::HALF, false, true, 2, 295141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 458, 255), 296141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 297141cc406Sopenharmony_ci 298141cc406Sopenharmony_ci {MotorId::MD_5345, 150, 3, StepType::HALF, false, true, 2, 299141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 687, 255), 300141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 301141cc406Sopenharmony_ci 302141cc406Sopenharmony_ci {MotorId::MD_5345, 200, 3, StepType::HALF, false, true, 2, 303141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 916, 255), 304141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 305141cc406Sopenharmony_ci 306141cc406Sopenharmony_ci {MotorId::MD_5345, 300, 3, StepType::HALF, false, true, 2, 307141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 1375, 255), 308141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 309141cc406Sopenharmony_ci 310141cc406Sopenharmony_ci {MotorId::MD_5345, 400, 3, StepType::HALF, false, true, 0, 311141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 1833, 32), 312141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 32}, 313141cc406Sopenharmony_ci 314141cc406Sopenharmony_ci {MotorId::MD_5345, 500, 3, StepType::HALF, false, true, 0, 315141cc406Sopenharmony_ci MotorSlope::create_from_steps(2291, 2291, 32), 316141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 32}, 317141cc406Sopenharmony_ci 318141cc406Sopenharmony_ci {MotorId::MD_5345, 600, 3, StepType::HALF, false, true, 0, 319141cc406Sopenharmony_ci MotorSlope::create_from_steps(2750, 2750, 32), 320141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 32}, 321141cc406Sopenharmony_ci 322141cc406Sopenharmony_ci {MotorId::MD_5345, 1200, 3, StepType::QUARTER, false, true, 0, 323141cc406Sopenharmony_ci MotorSlope::create_from_steps(2750, 2750, 16), 324141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 146}, 325141cc406Sopenharmony_ci 326141cc406Sopenharmony_ci {MotorId::MD_5345, 2400, 3, StepType::QUARTER, false, true, 0, 327141cc406Sopenharmony_ci MotorSlope::create_from_steps(5500, 5500, 16), 328141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 146}, 329141cc406Sopenharmony_ci 330141cc406Sopenharmony_ci {MotorId::MD_5345, 50, 1, StepType::HALF, false, true, 2, 331141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 250, 255), 332141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 333141cc406Sopenharmony_ci 334141cc406Sopenharmony_ci {MotorId::MD_5345, 75, 1, StepType::HALF, false, true, 2, 335141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 343, 255), 336141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 337141cc406Sopenharmony_ci 338141cc406Sopenharmony_ci {MotorId::MD_5345, 100, 1, StepType::HALF, false, true, 2, 339141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 458, 255), 340141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 341141cc406Sopenharmony_ci 342141cc406Sopenharmony_ci {MotorId::MD_5345, 150, 1, StepType::HALF, false, true, 2, 343141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 687, 255), 344141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 345141cc406Sopenharmony_ci 346141cc406Sopenharmony_ci {MotorId::MD_5345, 200, 1, StepType::HALF, false, true, 2, 347141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 916, 255), 348141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 349141cc406Sopenharmony_ci 350141cc406Sopenharmony_ci {MotorId::MD_5345, 300, 1, StepType::HALF, false, true, 2, 351141cc406Sopenharmony_ci MotorSlope::create_from_steps(2500, 1375, 255), 352141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 64}, 353141cc406Sopenharmony_ci 354141cc406Sopenharmony_ci {MotorId::MD_5345, 400, 1, StepType::HALF, false, true, 0, 355141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 1833, 32), 356141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 32}, 357141cc406Sopenharmony_ci 358141cc406Sopenharmony_ci {MotorId::MD_5345, 500, 1, StepType::HALF, false, true, 0, 359141cc406Sopenharmony_ci MotorSlope::create_from_steps(2291, 2291, 32), 360141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 32}, 361141cc406Sopenharmony_ci 362141cc406Sopenharmony_ci {MotorId::MD_5345, 600, 1, StepType::HALF, false, true, 0, 363141cc406Sopenharmony_ci MotorSlope::create_from_steps(2750, 2750, 32), 364141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 32}, 365141cc406Sopenharmony_ci 366141cc406Sopenharmony_ci {MotorId::MD_5345, 1200, 1, StepType::QUARTER, false, true, 0, 367141cc406Sopenharmony_ci MotorSlope::create_from_steps(2750, 2750, 16), 368141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 146}, 369141cc406Sopenharmony_ci 370141cc406Sopenharmony_ci {MotorId::MD_5345, 2400, 1, StepType::QUARTER, false, true, 0, 371141cc406Sopenharmony_ci MotorSlope::create_from_steps(5500, 5500, 16), 372141cc406Sopenharmony_ci MotorSlope::create_from_steps(2000, 300, 255), 146}, /* 5500 guessed */ 373141cc406Sopenharmony_ci}; 374141cc406Sopenharmony_ci 375141cc406Sopenharmony_ci/** 376141cc406Sopenharmony_ci * reads value from gpio endpoint 377141cc406Sopenharmony_ci */ 378141cc406Sopenharmony_cistatic void gl646_gpio_read(IUsbDevice& usb_dev, std::uint8_t* value) 379141cc406Sopenharmony_ci{ 380141cc406Sopenharmony_ci DBG_HELPER(dbg); 381141cc406Sopenharmony_ci usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, GPIO_READ, INDEX, 1, value); 382141cc406Sopenharmony_ci} 383141cc406Sopenharmony_ci 384141cc406Sopenharmony_ci/** 385141cc406Sopenharmony_ci * writes the given value to gpio endpoint 386141cc406Sopenharmony_ci */ 387141cc406Sopenharmony_cistatic void gl646_gpio_write(IUsbDevice& usb_dev, std::uint8_t value) 388141cc406Sopenharmony_ci{ 389141cc406Sopenharmony_ci DBG_HELPER_ARGS(dbg, "(0x%02x)", value); 390141cc406Sopenharmony_ci usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, GPIO_WRITE, INDEX, 1, &value); 391141cc406Sopenharmony_ci} 392141cc406Sopenharmony_ci 393141cc406Sopenharmony_ci/** 394141cc406Sopenharmony_ci * writes the given value to gpio output enable endpoint 395141cc406Sopenharmony_ci */ 396141cc406Sopenharmony_cistatic void gl646_gpio_output_enable(IUsbDevice& usb_dev, std::uint8_t value) 397141cc406Sopenharmony_ci{ 398141cc406Sopenharmony_ci DBG_HELPER_ARGS(dbg, "(0x%02x)", value); 399141cc406Sopenharmony_ci usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, GPIO_OUTPUT_ENABLE, INDEX, 1, &value); 400141cc406Sopenharmony_ci} 401141cc406Sopenharmony_ci 402141cc406Sopenharmony_ci/** 403141cc406Sopenharmony_ci * stop scanner's motor 404141cc406Sopenharmony_ci * @param dev scanner's device 405141cc406Sopenharmony_ci */ 406141cc406Sopenharmony_cistatic void gl646_stop_motor(Genesys_Device* dev) 407141cc406Sopenharmony_ci{ 408141cc406Sopenharmony_ci DBG_HELPER(dbg); 409141cc406Sopenharmony_ci dev->interface->write_register(0x0f, 0x00); 410141cc406Sopenharmony_ci} 411141cc406Sopenharmony_ci 412141cc406Sopenharmony_ci/** 413141cc406Sopenharmony_ci * Returns the cksel values used by the required scan mode. 414141cc406Sopenharmony_ci * @param sensor id of the sensor 415141cc406Sopenharmony_ci * @param required required resolution 416141cc406Sopenharmony_ci * @param color true is color mode 417141cc406Sopenharmony_ci * @return cksel value for mode 418141cc406Sopenharmony_ci */ 419141cc406Sopenharmony_cistatic int get_cksel(SensorId sensor_id, int required, unsigned channels) 420141cc406Sopenharmony_ci{ 421141cc406Sopenharmony_ci for (const auto& sensor : *s_sensors) { 422141cc406Sopenharmony_ci // exit on perfect match 423141cc406Sopenharmony_ci if (sensor.sensor_id == sensor_id && sensor.resolutions.matches(required) && 424141cc406Sopenharmony_ci sensor.matches_channel_count(channels)) 425141cc406Sopenharmony_ci { 426141cc406Sopenharmony_ci unsigned cksel = sensor.ccd_pixels_per_system_pixel(); 427141cc406Sopenharmony_ci return cksel; 428141cc406Sopenharmony_ci } 429141cc406Sopenharmony_ci } 430141cc406Sopenharmony_ci DBG(DBG_error, "%s: failed to find match for %d dpi\n", __func__, required); 431141cc406Sopenharmony_ci /* fail safe fallback */ 432141cc406Sopenharmony_ci return 1; 433141cc406Sopenharmony_ci} 434141cc406Sopenharmony_ci 435141cc406Sopenharmony_civoid CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, 436141cc406Sopenharmony_ci Genesys_Register_Set* regs, 437141cc406Sopenharmony_ci const ScanSession& session) const 438141cc406Sopenharmony_ci{ 439141cc406Sopenharmony_ci DBG_HELPER(dbg); 440141cc406Sopenharmony_ci session.assert_computed(); 441141cc406Sopenharmony_ci 442141cc406Sopenharmony_ci debug_dump(DBG_info, sensor); 443141cc406Sopenharmony_ci 444141cc406Sopenharmony_ci std::uint32_t move = session.params.starty; 445141cc406Sopenharmony_ci 446141cc406Sopenharmony_ci Motor_Master *motor = nullptr; 447141cc406Sopenharmony_ci std::uint32_t z1, z2; 448141cc406Sopenharmony_ci int feedl; 449141cc406Sopenharmony_ci 450141cc406Sopenharmony_ci 451141cc406Sopenharmony_ci /* for the given resolution, search for master 452141cc406Sopenharmony_ci * motor mode setting */ 453141cc406Sopenharmony_ci for (unsigned i = 0; i < sizeof (motor_master) / sizeof (Motor_Master); ++i) { 454141cc406Sopenharmony_ci if (dev->model->motor_id == motor_master[i].motor_id && 455141cc406Sopenharmony_ci motor_master[i].dpi == session.params.yres && 456141cc406Sopenharmony_ci motor_master[i].channels == session.params.channels) 457141cc406Sopenharmony_ci { 458141cc406Sopenharmony_ci motor = &motor_master[i]; 459141cc406Sopenharmony_ci } 460141cc406Sopenharmony_ci } 461141cc406Sopenharmony_ci if (motor == nullptr) { 462141cc406Sopenharmony_ci throw SaneException("unable to find settings for motor %d at %d dpi, color=%d", 463141cc406Sopenharmony_ci static_cast<unsigned>(dev->model->motor_id), 464141cc406Sopenharmony_ci session.params.yres, session.params.channels); 465141cc406Sopenharmony_ci } 466141cc406Sopenharmony_ci 467141cc406Sopenharmony_ci scanner_setup_sensor(*dev, sensor, *regs); 468141cc406Sopenharmony_ci 469141cc406Sopenharmony_ci /* now generate slope tables : we are not using generate_slope_table3 yet */ 470141cc406Sopenharmony_ci auto slope_table1 = create_slope_table_for_speed(motor->slope1, motor->slope1.max_speed_w, 471141cc406Sopenharmony_ci StepType::FULL, 1, 4, 472141cc406Sopenharmony_ci get_slope_table_max_size(AsicType::GL646)); 473141cc406Sopenharmony_ci auto slope_table2 = create_slope_table_for_speed(motor->slope2, motor->slope2.max_speed_w, 474141cc406Sopenharmony_ci StepType::FULL, 1, 4, 475141cc406Sopenharmony_ci get_slope_table_max_size(AsicType::GL646)); 476141cc406Sopenharmony_ci 477141cc406Sopenharmony_ci /* R01 */ 478141cc406Sopenharmony_ci /* now setup other registers for final scan (ie with shading enabled) */ 479141cc406Sopenharmony_ci /* watch dog + shading + scan enable */ 480141cc406Sopenharmony_ci regs->find_reg(0x01).value |= REG_0x01_DOGENB | REG_0x01_SCAN; 481141cc406Sopenharmony_ci if (dev->model->is_cis) { 482141cc406Sopenharmony_ci regs->find_reg(0x01).value |= REG_0x01_CISSET; 483141cc406Sopenharmony_ci } else { 484141cc406Sopenharmony_ci regs->find_reg(0x01).value &= ~REG_0x01_CISSET; 485141cc406Sopenharmony_ci } 486141cc406Sopenharmony_ci 487141cc406Sopenharmony_ci // if device has no calibration, don't enable shading correction 488141cc406Sopenharmony_ci if (has_flag(dev->model->flags, ModelFlag::DISABLE_SHADING_CALIBRATION) || 489141cc406Sopenharmony_ci has_flag(session.params.flags, ScanFlag::DISABLE_SHADING)) 490141cc406Sopenharmony_ci { 491141cc406Sopenharmony_ci regs->find_reg(0x01).value &= ~REG_0x01_DVDSET; 492141cc406Sopenharmony_ci } else { 493141cc406Sopenharmony_ci regs->find_reg(0x01).value |= REG_0x01_DVDSET; 494141cc406Sopenharmony_ci } 495141cc406Sopenharmony_ci 496141cc406Sopenharmony_ci regs->find_reg(0x01).value &= ~REG_0x01_FASTMOD; 497141cc406Sopenharmony_ci if (motor->fastmod) { 498141cc406Sopenharmony_ci regs->find_reg(0x01).value |= REG_0x01_FASTMOD; 499141cc406Sopenharmony_ci } 500141cc406Sopenharmony_ci 501141cc406Sopenharmony_ci /* R02 */ 502141cc406Sopenharmony_ci /* allow moving when buffer full by default */ 503141cc406Sopenharmony_ci if (!dev->model->is_sheetfed) { 504141cc406Sopenharmony_ci dev->reg.find_reg(0x02).value &= ~REG_0x02_ACDCDIS; 505141cc406Sopenharmony_ci } else { 506141cc406Sopenharmony_ci dev->reg.find_reg(0x02).value |= REG_0x02_ACDCDIS; 507141cc406Sopenharmony_ci } 508141cc406Sopenharmony_ci 509141cc406Sopenharmony_ci /* setup motor power and direction */ 510141cc406Sopenharmony_ci sanei_genesys_set_motor_power(*regs, true); 511141cc406Sopenharmony_ci 512141cc406Sopenharmony_ci if (has_flag(session.params.flags, ScanFlag::REVERSE)) { 513141cc406Sopenharmony_ci regs->find_reg(0x02).value |= REG_0x02_MTRREV; 514141cc406Sopenharmony_ci } else { 515141cc406Sopenharmony_ci regs->find_reg(0x02).value &= ~REG_0x02_MTRREV; 516141cc406Sopenharmony_ci } 517141cc406Sopenharmony_ci 518141cc406Sopenharmony_ci /* fastfed enabled (2 motor slope tables) */ 519141cc406Sopenharmony_ci if (motor->fastfed) { 520141cc406Sopenharmony_ci regs->find_reg(0x02).value |= REG_0x02_FASTFED; 521141cc406Sopenharmony_ci } else { 522141cc406Sopenharmony_ci regs->find_reg(0x02).value &= ~REG_0x02_FASTFED; 523141cc406Sopenharmony_ci } 524141cc406Sopenharmony_ci 525141cc406Sopenharmony_ci /* step type */ 526141cc406Sopenharmony_ci regs->find_reg(0x02).value &= ~REG_0x02_STEPSEL; 527141cc406Sopenharmony_ci switch (motor->steptype) 528141cc406Sopenharmony_ci { 529141cc406Sopenharmony_ci case StepType::FULL: 530141cc406Sopenharmony_ci break; 531141cc406Sopenharmony_ci case StepType::HALF: 532141cc406Sopenharmony_ci regs->find_reg(0x02).value |= 1; 533141cc406Sopenharmony_ci break; 534141cc406Sopenharmony_ci case StepType::QUARTER: 535141cc406Sopenharmony_ci regs->find_reg(0x02).value |= 2; 536141cc406Sopenharmony_ci break; 537141cc406Sopenharmony_ci default: 538141cc406Sopenharmony_ci regs->find_reg(0x02).value |= 3; 539141cc406Sopenharmony_ci break; 540141cc406Sopenharmony_ci } 541141cc406Sopenharmony_ci 542141cc406Sopenharmony_ci if (dev->model->is_sheetfed || !has_flag(session.params.flags, ScanFlag::AUTO_GO_HOME)) { 543141cc406Sopenharmony_ci regs->find_reg(0x02).value &= ~REG_0x02_AGOHOME; 544141cc406Sopenharmony_ci } else { 545141cc406Sopenharmony_ci regs->find_reg(0x02).value |= REG_0x02_AGOHOME; 546141cc406Sopenharmony_ci } 547141cc406Sopenharmony_ci 548141cc406Sopenharmony_ci /* R03 */ 549141cc406Sopenharmony_ci regs->find_reg(0x03).value &= ~REG_0x03_AVEENB; 550141cc406Sopenharmony_ci // regs->find_reg(0x03).value |= REG_0x03_AVEENB; 551141cc406Sopenharmony_ci regs->find_reg(0x03).value &= ~REG_0x03_LAMPDOG; 552141cc406Sopenharmony_ci 553141cc406Sopenharmony_ci /* select XPA */ 554141cc406Sopenharmony_ci regs->find_reg(0x03).value &= ~REG_0x03_XPASEL; 555141cc406Sopenharmony_ci if ((session.params.flags & ScanFlag::USE_XPA) != ScanFlag::NONE) { 556141cc406Sopenharmony_ci regs->find_reg(0x03).value |= REG_0x03_XPASEL; 557141cc406Sopenharmony_ci } 558141cc406Sopenharmony_ci regs->state.is_xpa_on = (session.params.flags & ScanFlag::USE_XPA) != ScanFlag::NONE; 559141cc406Sopenharmony_ci 560141cc406Sopenharmony_ci /* R04 */ 561141cc406Sopenharmony_ci /* monochrome / color scan */ 562141cc406Sopenharmony_ci switch (session.params.depth) { 563141cc406Sopenharmony_ci case 8: 564141cc406Sopenharmony_ci regs->find_reg(0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET); 565141cc406Sopenharmony_ci break; 566141cc406Sopenharmony_ci case 16: 567141cc406Sopenharmony_ci regs->find_reg(0x04).value &= ~REG_0x04_LINEART; 568141cc406Sopenharmony_ci regs->find_reg(0x04).value |= REG_0x04_BITSET; 569141cc406Sopenharmony_ci break; 570141cc406Sopenharmony_ci } 571141cc406Sopenharmony_ci 572141cc406Sopenharmony_ci sanei_genesys_set_dpihw(*regs, sensor.full_resolution); 573141cc406Sopenharmony_ci 574141cc406Sopenharmony_ci /* gamma enable for scans */ 575141cc406Sopenharmony_ci if (has_flag(dev->model->flags, ModelFlag::GAMMA_14BIT)) { 576141cc406Sopenharmony_ci regs->find_reg(0x05).value |= REG_0x05_GMM14BIT; 577141cc406Sopenharmony_ci } 578141cc406Sopenharmony_ci 579141cc406Sopenharmony_ci if (!has_flag(session.params.flags, ScanFlag::DISABLE_GAMMA) && 580141cc406Sopenharmony_ci session.params.depth < 16) 581141cc406Sopenharmony_ci { 582141cc406Sopenharmony_ci regs->find_reg(REG_0x05).value |= REG_0x05_GMMENB; 583141cc406Sopenharmony_ci } else { 584141cc406Sopenharmony_ci regs->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB; 585141cc406Sopenharmony_ci } 586141cc406Sopenharmony_ci 587141cc406Sopenharmony_ci /* true CIS gray if needed */ 588141cc406Sopenharmony_ci if (dev->model->is_cis && session.params.channels == 1 && 589141cc406Sopenharmony_ci session.params.color_filter == ColorFilter::NONE) 590141cc406Sopenharmony_ci { 591141cc406Sopenharmony_ci regs->find_reg(0x05).value |= REG_0x05_LEDADD; 592141cc406Sopenharmony_ci } else { 593141cc406Sopenharmony_ci regs->find_reg(0x05).value &= ~REG_0x05_LEDADD; 594141cc406Sopenharmony_ci } 595141cc406Sopenharmony_ci 596141cc406Sopenharmony_ci /* HP2400 1200dpi mode tuning */ 597141cc406Sopenharmony_ci 598141cc406Sopenharmony_ci if (dev->model->sensor_id == SensorId::CCD_HP2400) { 599141cc406Sopenharmony_ci /* reset count of dummy lines to zero */ 600141cc406Sopenharmony_ci regs->find_reg(0x1e).value &= ~REG_0x1E_LINESEL; 601141cc406Sopenharmony_ci if (session.params.xres >= 1200) { 602141cc406Sopenharmony_ci /* there must be one dummy line */ 603141cc406Sopenharmony_ci regs->find_reg(0x1e).value |= 1 & REG_0x1E_LINESEL; 604141cc406Sopenharmony_ci 605141cc406Sopenharmony_ci /* GPO12 need to be set to zero */ 606141cc406Sopenharmony_ci regs->find_reg(0x66).value &= ~0x20; 607141cc406Sopenharmony_ci } 608141cc406Sopenharmony_ci else 609141cc406Sopenharmony_ci { 610141cc406Sopenharmony_ci /* set GPO12 back to one */ 611141cc406Sopenharmony_ci regs->find_reg(0x66).value |= 0x20; 612141cc406Sopenharmony_ci } 613141cc406Sopenharmony_ci } 614141cc406Sopenharmony_ci 615141cc406Sopenharmony_ci /* motor steps used */ 616141cc406Sopenharmony_ci unsigned forward_steps = motor->fwdbwd; 617141cc406Sopenharmony_ci unsigned backward_steps = motor->fwdbwd; 618141cc406Sopenharmony_ci 619141cc406Sopenharmony_ci // the steps count must be different by at most 128, otherwise it's impossible to construct 620141cc406Sopenharmony_ci // a proper backtracking curve. We're using slightly lower limit to allow at least a minimum 621141cc406Sopenharmony_ci // distance between accelerations (forward_steps, backward_steps) 622141cc406Sopenharmony_ci if (slope_table1.table.size() > slope_table2.table.size() + 100) { 623141cc406Sopenharmony_ci slope_table2.expand_table(slope_table1.table.size() - 100, 1); 624141cc406Sopenharmony_ci } 625141cc406Sopenharmony_ci if (slope_table2.table.size() > slope_table1.table.size() + 100) { 626141cc406Sopenharmony_ci slope_table1.expand_table(slope_table2.table.size() - 100, 1); 627141cc406Sopenharmony_ci } 628141cc406Sopenharmony_ci 629141cc406Sopenharmony_ci if (slope_table1.table.size() >= slope_table2.table.size()) { 630141cc406Sopenharmony_ci backward_steps += (slope_table1.table.size() - slope_table2.table.size()) * 2; 631141cc406Sopenharmony_ci } else { 632141cc406Sopenharmony_ci forward_steps += (slope_table2.table.size() - slope_table1.table.size()) * 2; 633141cc406Sopenharmony_ci } 634141cc406Sopenharmony_ci 635141cc406Sopenharmony_ci if (forward_steps > 255) { 636141cc406Sopenharmony_ci if (backward_steps < (forward_steps - 255)) { 637141cc406Sopenharmony_ci throw SaneException("Can't set backtracking parameters without skipping image"); 638141cc406Sopenharmony_ci } 639141cc406Sopenharmony_ci backward_steps -= forward_steps - 255; 640141cc406Sopenharmony_ci } 641141cc406Sopenharmony_ci if (backward_steps > 255) { 642141cc406Sopenharmony_ci if (forward_steps < (backward_steps - 255)) { 643141cc406Sopenharmony_ci throw SaneException("Can't set backtracking parameters without skipping image"); 644141cc406Sopenharmony_ci } 645141cc406Sopenharmony_ci forward_steps -= backward_steps - 255; 646141cc406Sopenharmony_ci } 647141cc406Sopenharmony_ci 648141cc406Sopenharmony_ci regs->find_reg(0x21).value = slope_table1.table.size(); 649141cc406Sopenharmony_ci regs->find_reg(0x24).value = slope_table2.table.size(); 650141cc406Sopenharmony_ci regs->find_reg(0x22).value = forward_steps; 651141cc406Sopenharmony_ci regs->find_reg(0x23).value = backward_steps; 652141cc406Sopenharmony_ci 653141cc406Sopenharmony_ci /* CIS scanners read one line per color channel 654141cc406Sopenharmony_ci * since gray mode use 'add' we also read 3 channels even not in 655141cc406Sopenharmony_ci * color mode */ 656141cc406Sopenharmony_ci if (dev->model->is_cis) { 657141cc406Sopenharmony_ci regs->set24(REG_LINCNT, session.output_line_count * 3); 658141cc406Sopenharmony_ci } else { 659141cc406Sopenharmony_ci regs->set24(REG_LINCNT, session.output_line_count); 660141cc406Sopenharmony_ci } 661141cc406Sopenharmony_ci 662141cc406Sopenharmony_ci regs->set16(REG_STRPIXEL, session.pixel_startx); 663141cc406Sopenharmony_ci regs->set16(REG_ENDPIXEL, session.pixel_endx); 664141cc406Sopenharmony_ci 665141cc406Sopenharmony_ci regs->set24(REG_MAXWD, session.output_line_bytes); 666141cc406Sopenharmony_ci 667141cc406Sopenharmony_ci // FIXME: the incoming sensor is selected for incorrect resolution 668141cc406Sopenharmony_ci const auto& dpiset_sensor = sanei_genesys_find_sensor(dev, session.params.xres, 669141cc406Sopenharmony_ci session.params.channels, 670141cc406Sopenharmony_ci session.params.scan_method); 671141cc406Sopenharmony_ci regs->set16(REG_DPISET, dpiset_sensor.register_dpiset); 672141cc406Sopenharmony_ci regs->set16(REG_LPERIOD, sensor.exposure_lperiod); 673141cc406Sopenharmony_ci 674141cc406Sopenharmony_ci /* move distance must be adjusted to take into account the extra lines 675141cc406Sopenharmony_ci * read to reorder data */ 676141cc406Sopenharmony_ci feedl = move; 677141cc406Sopenharmony_ci 678141cc406Sopenharmony_ci if (session.num_staggered_lines + session.max_color_shift_lines > 0 && feedl != 0) { 679141cc406Sopenharmony_ci unsigned total_lines = session.max_color_shift_lines + session.num_staggered_lines; 680141cc406Sopenharmony_ci int feed_offset = (total_lines * dev->motor.base_ydpi) / motor->dpi; 681141cc406Sopenharmony_ci if (feedl > feed_offset) { 682141cc406Sopenharmony_ci feedl = feedl - feed_offset; 683141cc406Sopenharmony_ci } 684141cc406Sopenharmony_ci } 685141cc406Sopenharmony_ci 686141cc406Sopenharmony_ci /* we assume all scans are done with 2 tables */ 687141cc406Sopenharmony_ci /* 688141cc406Sopenharmony_ci feedl = feed_steps - fast_slope_steps*2 - 689141cc406Sopenharmony_ci (slow_slope_steps >> scan_step_type); */ 690141cc406Sopenharmony_ci /* but head has moved due to shading calibration => dev->scanhead_position_primary */ 691141cc406Sopenharmony_ci if (feedl > 0) 692141cc406Sopenharmony_ci { 693141cc406Sopenharmony_ci /* TODO clean up this when I'll fully understand. 694141cc406Sopenharmony_ci * for now, special casing each motor */ 695141cc406Sopenharmony_ci switch (dev->model->motor_id) { 696141cc406Sopenharmony_ci case MotorId::MD_5345: 697141cc406Sopenharmony_ci switch (motor->dpi) { 698141cc406Sopenharmony_ci case 200: 699141cc406Sopenharmony_ci feedl -= 70; 700141cc406Sopenharmony_ci break; 701141cc406Sopenharmony_ci case 300: 702141cc406Sopenharmony_ci feedl -= 70; 703141cc406Sopenharmony_ci break; 704141cc406Sopenharmony_ci case 400: 705141cc406Sopenharmony_ci feedl += 130; 706141cc406Sopenharmony_ci break; 707141cc406Sopenharmony_ci case 600: 708141cc406Sopenharmony_ci feedl += 160; 709141cc406Sopenharmony_ci break; 710141cc406Sopenharmony_ci case 1200: 711141cc406Sopenharmony_ci feedl += 160; 712141cc406Sopenharmony_ci break; 713141cc406Sopenharmony_ci case 2400: 714141cc406Sopenharmony_ci feedl += 180; 715141cc406Sopenharmony_ci break; 716141cc406Sopenharmony_ci default: 717141cc406Sopenharmony_ci break; 718141cc406Sopenharmony_ci } 719141cc406Sopenharmony_ci break; 720141cc406Sopenharmony_ci case MotorId::HP2300: 721141cc406Sopenharmony_ci switch (motor->dpi) { 722141cc406Sopenharmony_ci case 75: 723141cc406Sopenharmony_ci feedl -= 180; 724141cc406Sopenharmony_ci break; 725141cc406Sopenharmony_ci case 150: 726141cc406Sopenharmony_ci feedl += 0; 727141cc406Sopenharmony_ci break; 728141cc406Sopenharmony_ci case 300: 729141cc406Sopenharmony_ci feedl += 30; 730141cc406Sopenharmony_ci break; 731141cc406Sopenharmony_ci case 600: 732141cc406Sopenharmony_ci feedl += 35; 733141cc406Sopenharmony_ci break; 734141cc406Sopenharmony_ci case 1200: 735141cc406Sopenharmony_ci feedl += 45; 736141cc406Sopenharmony_ci break; 737141cc406Sopenharmony_ci default: 738141cc406Sopenharmony_ci break; 739141cc406Sopenharmony_ci } 740141cc406Sopenharmony_ci break; 741141cc406Sopenharmony_ci case MotorId::HP2400: 742141cc406Sopenharmony_ci switch (motor->dpi) { 743141cc406Sopenharmony_ci case 150: 744141cc406Sopenharmony_ci feedl += 150; 745141cc406Sopenharmony_ci break; 746141cc406Sopenharmony_ci case 300: 747141cc406Sopenharmony_ci feedl += 220; 748141cc406Sopenharmony_ci break; 749141cc406Sopenharmony_ci case 600: 750141cc406Sopenharmony_ci feedl += 260; 751141cc406Sopenharmony_ci break; 752141cc406Sopenharmony_ci case 1200: 753141cc406Sopenharmony_ci feedl += 280; /* 300 */ 754141cc406Sopenharmony_ci break; 755141cc406Sopenharmony_ci case 50: 756141cc406Sopenharmony_ci feedl += 0; 757141cc406Sopenharmony_ci break; 758141cc406Sopenharmony_ci case 100: 759141cc406Sopenharmony_ci feedl += 100; 760141cc406Sopenharmony_ci break; 761141cc406Sopenharmony_ci default: 762141cc406Sopenharmony_ci break; 763141cc406Sopenharmony_ci } 764141cc406Sopenharmony_ci break; 765141cc406Sopenharmony_ci 766141cc406Sopenharmony_ci /* theorical value */ 767141cc406Sopenharmony_ci default: { 768141cc406Sopenharmony_ci unsigned step_shift = static_cast<unsigned>(motor->steptype); 769141cc406Sopenharmony_ci 770141cc406Sopenharmony_ci if (motor->fastfed) 771141cc406Sopenharmony_ci { 772141cc406Sopenharmony_ci feedl = feedl - 2 * slope_table2.table.size() - 773141cc406Sopenharmony_ci (slope_table1.table.size() >> step_shift); 774141cc406Sopenharmony_ci } 775141cc406Sopenharmony_ci else 776141cc406Sopenharmony_ci { 777141cc406Sopenharmony_ci feedl = feedl - (slope_table1.table.size() >> step_shift); 778141cc406Sopenharmony_ci } 779141cc406Sopenharmony_ci break; 780141cc406Sopenharmony_ci } 781141cc406Sopenharmony_ci } 782141cc406Sopenharmony_ci /* security */ 783141cc406Sopenharmony_ci if (feedl < 0) 784141cc406Sopenharmony_ci feedl = 0; 785141cc406Sopenharmony_ci } 786141cc406Sopenharmony_ci 787141cc406Sopenharmony_ci regs->set24(REG_FEEDL, feedl); 788141cc406Sopenharmony_ci 789141cc406Sopenharmony_ci regs->find_reg(0x65).value = motor->mtrpwm; 790141cc406Sopenharmony_ci 791141cc406Sopenharmony_ci sanei_genesys_calculate_zmod(regs->find_reg(0x02).value & REG_0x02_FASTFED, 792141cc406Sopenharmony_ci sensor.exposure_lperiod, 793141cc406Sopenharmony_ci slope_table1.table, 794141cc406Sopenharmony_ci slope_table1.table.size(), 795141cc406Sopenharmony_ci move, motor->fwdbwd, &z1, &z2); 796141cc406Sopenharmony_ci 797141cc406Sopenharmony_ci /* no z1/z2 for sheetfed scanners */ 798141cc406Sopenharmony_ci if (dev->model->is_sheetfed) { 799141cc406Sopenharmony_ci z1 = 0; 800141cc406Sopenharmony_ci z2 = 0; 801141cc406Sopenharmony_ci } 802141cc406Sopenharmony_ci regs->set16(REG_Z1MOD, z1); 803141cc406Sopenharmony_ci regs->set16(REG_Z2MOD, z2); 804141cc406Sopenharmony_ci regs->find_reg(0x6b).value = slope_table2.table.size(); 805141cc406Sopenharmony_ci regs->find_reg(0x6c).value = 806141cc406Sopenharmony_ci (regs->find_reg(0x6c).value & REG_0x6C_TGTIME) | ((z1 >> 13) & 0x38) | ((z2 >> 16) 807141cc406Sopenharmony_ci & 0x07); 808141cc406Sopenharmony_ci 809141cc406Sopenharmony_ci write_control(dev, sensor, session.output_resolution); 810141cc406Sopenharmony_ci 811141cc406Sopenharmony_ci // setup analog frontend 812141cc406Sopenharmony_ci gl646_set_fe(dev, sensor, AFE_SET, session.output_resolution); 813141cc406Sopenharmony_ci 814141cc406Sopenharmony_ci setup_image_pipeline(*dev, session); 815141cc406Sopenharmony_ci 816141cc406Sopenharmony_ci dev->read_active = true; 817141cc406Sopenharmony_ci 818141cc406Sopenharmony_ci dev->session = session; 819141cc406Sopenharmony_ci 820141cc406Sopenharmony_ci dev->total_bytes_read = 0; 821141cc406Sopenharmony_ci dev->total_bytes_to_read = (size_t) session.output_line_bytes_requested 822141cc406Sopenharmony_ci * (size_t) session.params.lines; 823141cc406Sopenharmony_ci 824141cc406Sopenharmony_ci /* select color filter based on settings */ 825141cc406Sopenharmony_ci regs->find_reg(0x04).value &= ~REG_0x04_FILTER; 826141cc406Sopenharmony_ci if (session.params.channels == 1) { 827141cc406Sopenharmony_ci switch (session.params.color_filter) { 828141cc406Sopenharmony_ci case ColorFilter::RED: 829141cc406Sopenharmony_ci regs->find_reg(0x04).value |= 0x04; 830141cc406Sopenharmony_ci break; 831141cc406Sopenharmony_ci case ColorFilter::GREEN: 832141cc406Sopenharmony_ci regs->find_reg(0x04).value |= 0x08; 833141cc406Sopenharmony_ci break; 834141cc406Sopenharmony_ci case ColorFilter::BLUE: 835141cc406Sopenharmony_ci regs->find_reg(0x04).value |= 0x0c; 836141cc406Sopenharmony_ci break; 837141cc406Sopenharmony_ci default: 838141cc406Sopenharmony_ci break; 839141cc406Sopenharmony_ci } 840141cc406Sopenharmony_ci } 841141cc406Sopenharmony_ci 842141cc406Sopenharmony_ci scanner_send_slope_table(dev, sensor, 0, slope_table1.table); 843141cc406Sopenharmony_ci scanner_send_slope_table(dev, sensor, 1, slope_table2.table); 844141cc406Sopenharmony_ci} 845141cc406Sopenharmony_ci 846141cc406Sopenharmony_ci/** 847141cc406Sopenharmony_ci * Set all registers to default values after init 848141cc406Sopenharmony_ci * @param dev scannerr's device to set 849141cc406Sopenharmony_ci */ 850141cc406Sopenharmony_cistatic void 851141cc406Sopenharmony_cigl646_init_regs (Genesys_Device * dev) 852141cc406Sopenharmony_ci{ 853141cc406Sopenharmony_ci int addr; 854141cc406Sopenharmony_ci 855141cc406Sopenharmony_ci DBG(DBG_proc, "%s\n", __func__); 856141cc406Sopenharmony_ci 857141cc406Sopenharmony_ci dev->reg.clear(); 858141cc406Sopenharmony_ci 859141cc406Sopenharmony_ci for (addr = 1; addr <= 0x0b; addr++) 860141cc406Sopenharmony_ci dev->reg.init_reg(addr, 0); 861141cc406Sopenharmony_ci for (addr = 0x10; addr <= 0x29; addr++) 862141cc406Sopenharmony_ci dev->reg.init_reg(addr, 0); 863141cc406Sopenharmony_ci for (addr = 0x2c; addr <= 0x39; addr++) 864141cc406Sopenharmony_ci dev->reg.init_reg(addr, 0); 865141cc406Sopenharmony_ci for (addr = 0x3d; addr <= 0x3f; addr++) 866141cc406Sopenharmony_ci dev->reg.init_reg(addr, 0); 867141cc406Sopenharmony_ci for (addr = 0x52; addr <= 0x5e; addr++) 868141cc406Sopenharmony_ci dev->reg.init_reg(addr, 0); 869141cc406Sopenharmony_ci for (addr = 0x60; addr <= 0x6d; addr++) 870141cc406Sopenharmony_ci dev->reg.init_reg(addr, 0); 871141cc406Sopenharmony_ci 872141cc406Sopenharmony_ci dev->reg.find_reg(0x01).value = 0x20 /*0x22 */ ; /* enable shading, CCD, color, 1M */ 873141cc406Sopenharmony_ci dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */ 874141cc406Sopenharmony_ci if (dev->model->motor_id == MotorId::MD_5345) { 875141cc406Sopenharmony_ci dev->reg.find_reg(0x02).value |= 0x01; // half-step 876141cc406Sopenharmony_ci } 877141cc406Sopenharmony_ci switch (dev->model->motor_id) { 878141cc406Sopenharmony_ci case MotorId::MD_5345: 879141cc406Sopenharmony_ci dev->reg.find_reg(0x02).value |= 0x01; /* half-step */ 880141cc406Sopenharmony_ci break; 881141cc406Sopenharmony_ci case MotorId::XP200: 882141cc406Sopenharmony_ci /* for this sheetfed scanner, no AGOHOME, nor backtracking */ 883141cc406Sopenharmony_ci dev->reg.find_reg(0x02).value = 0x50; 884141cc406Sopenharmony_ci break; 885141cc406Sopenharmony_ci default: 886141cc406Sopenharmony_ci break; 887141cc406Sopenharmony_ci } 888141cc406Sopenharmony_ci dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */ 889141cc406Sopenharmony_ci dev->reg.find_reg(0x04).value = 0x13 /*0x03 */ ; /* 8 bits data, 16 bits A/D, color, Wolfson fe *//* todo: according to spec, 0x0 is reserved? */ 890141cc406Sopenharmony_ci switch (dev->model->adc_id) 891141cc406Sopenharmony_ci { 892141cc406Sopenharmony_ci case AdcId::AD_XP200: 893141cc406Sopenharmony_ci dev->reg.find_reg(0x04).value = 0x12; 894141cc406Sopenharmony_ci break; 895141cc406Sopenharmony_ci default: 896141cc406Sopenharmony_ci /* Wolfson frontend */ 897141cc406Sopenharmony_ci dev->reg.find_reg(0x04).value = 0x13; 898141cc406Sopenharmony_ci break; 899141cc406Sopenharmony_ci } 900141cc406Sopenharmony_ci 901141cc406Sopenharmony_ci const auto& sensor = sanei_genesys_find_sensor_any(dev); 902141cc406Sopenharmony_ci 903141cc406Sopenharmony_ci dev->reg.find_reg(0x05).value = 0x00; /* 12 bits gamma, disable gamma, 24 clocks/pixel */ 904141cc406Sopenharmony_ci sanei_genesys_set_dpihw(dev->reg, sensor.full_resolution); 905141cc406Sopenharmony_ci 906141cc406Sopenharmony_ci if (has_flag(dev->model->flags, ModelFlag::GAMMA_14BIT)) { 907141cc406Sopenharmony_ci dev->reg.find_reg(0x05).value |= REG_0x05_GMM14BIT; 908141cc406Sopenharmony_ci } 909141cc406Sopenharmony_ci if (dev->model->adc_id == AdcId::AD_XP200) { 910141cc406Sopenharmony_ci dev->reg.find_reg(0x05).value |= 0x01; /* 12 clocks/pixel */ 911141cc406Sopenharmony_ci } 912141cc406Sopenharmony_ci 913141cc406Sopenharmony_ci if (dev->model->sensor_id == SensorId::CCD_HP2300) { 914141cc406Sopenharmony_ci dev->reg.find_reg(0x06).value = 0x00; // PWRBIT off, shading gain=4, normal AFE image capture 915141cc406Sopenharmony_ci } else { 916141cc406Sopenharmony_ci dev->reg.find_reg(0x06).value = 0x18; // PWRBIT on, shading gain=8, normal AFE image capture 917141cc406Sopenharmony_ci } 918141cc406Sopenharmony_ci 919141cc406Sopenharmony_ci scanner_setup_sensor(*dev, sensor, dev->reg); 920141cc406Sopenharmony_ci 921141cc406Sopenharmony_ci dev->reg.find_reg(0x1e).value = 0xf0; /* watch-dog time */ 922141cc406Sopenharmony_ci 923141cc406Sopenharmony_ci switch (dev->model->sensor_id) 924141cc406Sopenharmony_ci { 925141cc406Sopenharmony_ci case SensorId::CCD_HP2300: 926141cc406Sopenharmony_ci dev->reg.find_reg(0x1e).value = 0xf0; 927141cc406Sopenharmony_ci dev->reg.find_reg(0x1f).value = 0x10; 928141cc406Sopenharmony_ci dev->reg.find_reg(0x20).value = 0x20; 929141cc406Sopenharmony_ci break; 930141cc406Sopenharmony_ci case SensorId::CCD_HP2400: 931141cc406Sopenharmony_ci dev->reg.find_reg(0x1e).value = 0x80; 932141cc406Sopenharmony_ci dev->reg.find_reg(0x1f).value = 0x10; 933141cc406Sopenharmony_ci dev->reg.find_reg(0x20).value = 0x20; 934141cc406Sopenharmony_ci break; 935141cc406Sopenharmony_ci case SensorId::CCD_HP3670: 936141cc406Sopenharmony_ci dev->reg.find_reg(0x19).value = 0x2a; 937141cc406Sopenharmony_ci dev->reg.find_reg(0x1e).value = 0x80; 938141cc406Sopenharmony_ci dev->reg.find_reg(0x1f).value = 0x10; 939141cc406Sopenharmony_ci dev->reg.find_reg(0x20).value = 0x20; 940141cc406Sopenharmony_ci break; 941141cc406Sopenharmony_ci case SensorId::CIS_XP200: 942141cc406Sopenharmony_ci dev->reg.find_reg(0x1e).value = 0x10; 943141cc406Sopenharmony_ci dev->reg.find_reg(0x1f).value = 0x01; 944141cc406Sopenharmony_ci dev->reg.find_reg(0x20).value = 0x50; 945141cc406Sopenharmony_ci break; 946141cc406Sopenharmony_ci default: 947141cc406Sopenharmony_ci dev->reg.find_reg(0x1f).value = 0x01; 948141cc406Sopenharmony_ci dev->reg.find_reg(0x20).value = 0x50; 949141cc406Sopenharmony_ci break; 950141cc406Sopenharmony_ci } 951141cc406Sopenharmony_ci 952141cc406Sopenharmony_ci dev->reg.find_reg(0x21).value = 0x08 /*0x20 */ ; /* table one steps number for forward slope curve of the acc/dec */ 953141cc406Sopenharmony_ci dev->reg.find_reg(0x22).value = 0x10 /*0x08 */ ; /* steps number of the forward steps for start/stop */ 954141cc406Sopenharmony_ci dev->reg.find_reg(0x23).value = 0x10 /*0x08 */ ; /* steps number of the backward steps for start/stop */ 955141cc406Sopenharmony_ci dev->reg.find_reg(0x24).value = 0x08 /*0x20 */ ; /* table one steps number backward slope curve of the acc/dec */ 956141cc406Sopenharmony_ci dev->reg.find_reg(0x25).value = 0x00; /* scan line numbers (7000) */ 957141cc406Sopenharmony_ci dev->reg.find_reg(0x26).value = 0x00 /*0x1b */ ; 958141cc406Sopenharmony_ci dev->reg.find_reg(0x27).value = 0xd4 /*0x58 */ ; 959141cc406Sopenharmony_ci dev->reg.find_reg(0x28).value = 0x01; /* PWM duty for lamp control */ 960141cc406Sopenharmony_ci dev->reg.find_reg(0x29).value = 0xff; 961141cc406Sopenharmony_ci 962141cc406Sopenharmony_ci dev->reg.find_reg(0x2c).value = 0x02; /* set resolution (600 DPI) */ 963141cc406Sopenharmony_ci dev->reg.find_reg(0x2d).value = 0x58; 964141cc406Sopenharmony_ci dev->reg.find_reg(0x2e).value = 0x78; /* set black&white threshold high level */ 965141cc406Sopenharmony_ci dev->reg.find_reg(0x2f).value = 0x7f; /* set black&white threshold low level */ 966141cc406Sopenharmony_ci 967141cc406Sopenharmony_ci dev->reg.find_reg(0x30).value = 0x00; /* begin pixel position (16) */ 968141cc406Sopenharmony_ci dev->reg.find_reg(0x31).value = sensor.dummy_pixel /*0x10 */ ; /* TGW + 2*TG_SHLD + x */ 969141cc406Sopenharmony_ci dev->reg.find_reg(0x32).value = 0x2a /*0x15 */ ; /* end pixel position (5390) */ 970141cc406Sopenharmony_ci dev->reg.find_reg(0x33).value = 0xf8 /*0x0e */ ; /* TGW + 2*TG_SHLD + y */ 971141cc406Sopenharmony_ci dev->reg.find_reg(0x34).value = sensor.dummy_pixel; 972141cc406Sopenharmony_ci dev->reg.find_reg(0x35).value = 0x01 /*0x00 */ ; /* set maximum word size per line, for buffer full control (10800) */ 973141cc406Sopenharmony_ci dev->reg.find_reg(0x36).value = 0x00 /*0x2a */ ; 974141cc406Sopenharmony_ci dev->reg.find_reg(0x37).value = 0x00 /*0x30 */ ; 975141cc406Sopenharmony_ci dev->reg.find_reg(0x38).value = 0x2a; // line period (exposure time = 11000 pixels) */ 976141cc406Sopenharmony_ci dev->reg.find_reg(0x39).value = 0xf8; 977141cc406Sopenharmony_ci dev->reg.find_reg(0x3d).value = 0x00; /* set feed steps number of motor move */ 978141cc406Sopenharmony_ci dev->reg.find_reg(0x3e).value = 0x00; 979141cc406Sopenharmony_ci dev->reg.find_reg(0x3f).value = 0x01 /*0x00 */ ; 980141cc406Sopenharmony_ci 981141cc406Sopenharmony_ci dev->reg.find_reg(0x60).value = 0x00; /* Z1MOD, 60h:61h:(6D b5:b3), remainder for start/stop */ 982141cc406Sopenharmony_ci dev->reg.find_reg(0x61).value = 0x00; /* (21h+22h)/LPeriod */ 983141cc406Sopenharmony_ci dev->reg.find_reg(0x62).value = 0x00; /* Z2MODE, 62h:63h:(6D b2:b0), remainder for start scan */ 984141cc406Sopenharmony_ci dev->reg.find_reg(0x63).value = 0x00; /* (3Dh+3Eh+3Fh)/LPeriod for one-table mode,(21h+1Fh)/LPeriod */ 985141cc406Sopenharmony_ci dev->reg.find_reg(0x64).value = 0x00; /* motor PWM frequency */ 986141cc406Sopenharmony_ci dev->reg.find_reg(0x65).value = 0x00; /* PWM duty cycle for table one motor phase (63 = max) */ 987141cc406Sopenharmony_ci if (dev->model->motor_id == MotorId::MD_5345) { 988141cc406Sopenharmony_ci // PWM duty cycle for table one motor phase (63 = max) 989141cc406Sopenharmony_ci dev->reg.find_reg(0x65).value = 0x02; 990141cc406Sopenharmony_ci } 991141cc406Sopenharmony_ci 992141cc406Sopenharmony_ci for (const auto& reg : dev->gpo.regs) { 993141cc406Sopenharmony_ci dev->reg.set8(reg.address, reg.value); 994141cc406Sopenharmony_ci } 995141cc406Sopenharmony_ci 996141cc406Sopenharmony_ci switch (dev->model->motor_id) { 997141cc406Sopenharmony_ci case MotorId::HP2300: 998141cc406Sopenharmony_ci case MotorId::HP2400: 999141cc406Sopenharmony_ci dev->reg.find_reg(0x6a).value = 0x7f; /* table two steps number for acc/dec */ 1000141cc406Sopenharmony_ci dev->reg.find_reg(0x6b).value = 0x78; /* table two steps number for acc/dec */ 1001141cc406Sopenharmony_ci dev->reg.find_reg(0x6d).value = 0x7f; 1002141cc406Sopenharmony_ci break; 1003141cc406Sopenharmony_ci case MotorId::MD_5345: 1004141cc406Sopenharmony_ci dev->reg.find_reg(0x6a).value = 0x42; /* table two fast moving step type, PWM duty for table two */ 1005141cc406Sopenharmony_ci dev->reg.find_reg(0x6b).value = 0xff; /* table two steps number for acc/dec */ 1006141cc406Sopenharmony_ci dev->reg.find_reg(0x6d).value = 0x41; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ 1007141cc406Sopenharmony_ci break; 1008141cc406Sopenharmony_ci case MotorId::XP200: 1009141cc406Sopenharmony_ci dev->reg.find_reg(0x6a).value = 0x7f; /* table two fast moving step type, PWM duty for table two */ 1010141cc406Sopenharmony_ci dev->reg.find_reg(0x6b).value = 0x08; /* table two steps number for acc/dec */ 1011141cc406Sopenharmony_ci dev->reg.find_reg(0x6d).value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ 1012141cc406Sopenharmony_ci break; 1013141cc406Sopenharmony_ci case MotorId::HP3670: 1014141cc406Sopenharmony_ci dev->reg.find_reg(0x6a).value = 0x41; /* table two steps number for acc/dec */ 1015141cc406Sopenharmony_ci dev->reg.find_reg(0x6b).value = 0xc8; /* table two steps number for acc/dec */ 1016141cc406Sopenharmony_ci dev->reg.find_reg(0x6d).value = 0x7f; 1017141cc406Sopenharmony_ci break; 1018141cc406Sopenharmony_ci default: 1019141cc406Sopenharmony_ci dev->reg.find_reg(0x6a).value = 0x40; /* table two fast moving step type, PWM duty for table two */ 1020141cc406Sopenharmony_ci dev->reg.find_reg(0x6b).value = 0xff; /* table two steps number for acc/dec */ 1021141cc406Sopenharmony_ci dev->reg.find_reg(0x6d).value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ 1022141cc406Sopenharmony_ci break; 1023141cc406Sopenharmony_ci } 1024141cc406Sopenharmony_ci dev->reg.find_reg(0x6c).value = 0x00; /* period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE (one period time) */ 1025141cc406Sopenharmony_ci} 1026141cc406Sopenharmony_ci 1027141cc406Sopenharmony_ci// Set values of Analog Device type frontend 1028141cc406Sopenharmony_cistatic void gl646_set_ad_fe(Genesys_Device* dev, std::uint8_t set) 1029141cc406Sopenharmony_ci{ 1030141cc406Sopenharmony_ci DBG_HELPER(dbg); 1031141cc406Sopenharmony_ci int i; 1032141cc406Sopenharmony_ci 1033141cc406Sopenharmony_ci if (set == AFE_INIT) { 1034141cc406Sopenharmony_ci 1035141cc406Sopenharmony_ci dev->frontend = dev->frontend_initial; 1036141cc406Sopenharmony_ci 1037141cc406Sopenharmony_ci // write them to analog frontend 1038141cc406Sopenharmony_ci dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); 1039141cc406Sopenharmony_ci dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); 1040141cc406Sopenharmony_ci } 1041141cc406Sopenharmony_ci if (set == AFE_SET) 1042141cc406Sopenharmony_ci { 1043141cc406Sopenharmony_ci for (i = 0; i < 3; i++) { 1044141cc406Sopenharmony_ci dev->interface->write_fe_register(0x02 + i, dev->frontend.get_gain(i)); 1045141cc406Sopenharmony_ci } 1046141cc406Sopenharmony_ci for (i = 0; i < 3; i++) { 1047141cc406Sopenharmony_ci dev->interface->write_fe_register(0x05 + i, dev->frontend.get_offset(i)); 1048141cc406Sopenharmony_ci } 1049141cc406Sopenharmony_ci } 1050141cc406Sopenharmony_ci /* 1051141cc406Sopenharmony_ci if (set == AFE_POWER_SAVE) 1052141cc406Sopenharmony_ci { 1053141cc406Sopenharmony_ci dev->interface->write_fe_register(0x00, dev->frontend.reg[0] | 0x04); 1054141cc406Sopenharmony_ci } */ 1055141cc406Sopenharmony_ci} 1056141cc406Sopenharmony_ci 1057141cc406Sopenharmony_ci/** set up analog frontend 1058141cc406Sopenharmony_ci * set up analog frontend 1059141cc406Sopenharmony_ci * @param dev device to set up 1060141cc406Sopenharmony_ci * @param set action from AFE_SET, AFE_INIT and AFE_POWERSAVE 1061141cc406Sopenharmony_ci * @param dpi resolution of the scan since it affects settings 1062141cc406Sopenharmony_ci */ 1063141cc406Sopenharmony_cistatic void gl646_wm_hp3670(Genesys_Device* dev, const Genesys_Sensor& sensor, std::uint8_t set, 1064141cc406Sopenharmony_ci unsigned dpi) 1065141cc406Sopenharmony_ci{ 1066141cc406Sopenharmony_ci DBG_HELPER(dbg); 1067141cc406Sopenharmony_ci int i; 1068141cc406Sopenharmony_ci 1069141cc406Sopenharmony_ci switch (set) 1070141cc406Sopenharmony_ci { 1071141cc406Sopenharmony_ci case AFE_INIT: 1072141cc406Sopenharmony_ci dev->interface->write_fe_register(0x04, 0x80); 1073141cc406Sopenharmony_ci dev->interface->sleep_ms(200); 1074141cc406Sopenharmony_ci dev->interface->write_register(0x50, 0x00); 1075141cc406Sopenharmony_ci dev->frontend = dev->frontend_initial; 1076141cc406Sopenharmony_ci dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); 1077141cc406Sopenharmony_ci dev->interface->write_fe_register(0x02, dev->frontend.regs.get_value(0x02)); 1078141cc406Sopenharmony_ci gl646_gpio_output_enable(dev->interface->get_usb_device(), 0x07); 1079141cc406Sopenharmony_ci break; 1080141cc406Sopenharmony_ci case AFE_POWER_SAVE: 1081141cc406Sopenharmony_ci dev->interface->write_fe_register(0x01, 0x06); 1082141cc406Sopenharmony_ci dev->interface->write_fe_register(0x06, 0x0f); 1083141cc406Sopenharmony_ci return; 1084141cc406Sopenharmony_ci break; 1085141cc406Sopenharmony_ci default: /* AFE_SET */ 1086141cc406Sopenharmony_ci /* mode setup */ 1087141cc406Sopenharmony_ci i = dev->frontend.regs.get_value(0x03); 1088141cc406Sopenharmony_ci if (dpi > sensor.full_resolution / 2) { 1089141cc406Sopenharmony_ci /* fe_reg_0x03 must be 0x12 for 1200 dpi in WOLFSON_HP3670. 1090141cc406Sopenharmony_ci * WOLFSON_HP2400 in 1200 dpi mode works well with 1091141cc406Sopenharmony_ci * fe_reg_0x03 set to 0x32 or 0x12 but not to 0x02 */ 1092141cc406Sopenharmony_ci i = 0x12; 1093141cc406Sopenharmony_ci } 1094141cc406Sopenharmony_ci dev->interface->write_fe_register(0x03, i); 1095141cc406Sopenharmony_ci /* offset and sign (or msb/lsb ?) */ 1096141cc406Sopenharmony_ci for (i = 0; i < 3; i++) { 1097141cc406Sopenharmony_ci dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i)); 1098141cc406Sopenharmony_ci dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i)); 1099141cc406Sopenharmony_ci } 1100141cc406Sopenharmony_ci 1101141cc406Sopenharmony_ci // gain 1102141cc406Sopenharmony_ci for (i = 0; i < 3; i++) { 1103141cc406Sopenharmony_ci dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i)); 1104141cc406Sopenharmony_ci } 1105141cc406Sopenharmony_ci } 1106141cc406Sopenharmony_ci} 1107141cc406Sopenharmony_ci 1108141cc406Sopenharmony_ci/** Set values of analog frontend 1109141cc406Sopenharmony_ci * @param dev device to set 1110141cc406Sopenharmony_ci * @param set action to execute 1111141cc406Sopenharmony_ci * @param dpi dpi to setup the AFE 1112141cc406Sopenharmony_ci */ 1113141cc406Sopenharmony_cistatic void gl646_set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, std::uint8_t set, 1114141cc406Sopenharmony_ci int dpi) 1115141cc406Sopenharmony_ci{ 1116141cc406Sopenharmony_ci DBG_HELPER_ARGS(dbg, "%s,%d", set == AFE_INIT ? "init" : 1117141cc406Sopenharmony_ci set == AFE_SET ? "set" : 1118141cc406Sopenharmony_ci set == AFE_POWER_SAVE ? "powersave" : "huh?", dpi); 1119141cc406Sopenharmony_ci int i; 1120141cc406Sopenharmony_ci std::uint8_t val; 1121141cc406Sopenharmony_ci 1122141cc406Sopenharmony_ci /* Analog Device type frontend */ 1123141cc406Sopenharmony_ci std::uint8_t frontend_type = dev->reg.find_reg(0x04).value & REG_0x04_FESET; 1124141cc406Sopenharmony_ci if (frontend_type == 0x02) { 1125141cc406Sopenharmony_ci gl646_set_ad_fe(dev, set); 1126141cc406Sopenharmony_ci return; 1127141cc406Sopenharmony_ci } 1128141cc406Sopenharmony_ci 1129141cc406Sopenharmony_ci /* Wolfson type frontend */ 1130141cc406Sopenharmony_ci if (frontend_type != 0x03) { 1131141cc406Sopenharmony_ci throw SaneException("unsupported frontend type %d", frontend_type); 1132141cc406Sopenharmony_ci } 1133141cc406Sopenharmony_ci 1134141cc406Sopenharmony_ci /* per frontend function to keep code clean */ 1135141cc406Sopenharmony_ci switch (dev->model->adc_id) 1136141cc406Sopenharmony_ci { 1137141cc406Sopenharmony_ci case AdcId::WOLFSON_HP3670: 1138141cc406Sopenharmony_ci case AdcId::WOLFSON_HP2400: 1139141cc406Sopenharmony_ci gl646_wm_hp3670(dev, sensor, set, dpi); 1140141cc406Sopenharmony_ci return; 1141141cc406Sopenharmony_ci default: 1142141cc406Sopenharmony_ci DBG(DBG_proc, "%s(): using old method\n", __func__); 1143141cc406Sopenharmony_ci break; 1144141cc406Sopenharmony_ci } 1145141cc406Sopenharmony_ci 1146141cc406Sopenharmony_ci /* initialize analog frontend */ 1147141cc406Sopenharmony_ci if (set == AFE_INIT) { 1148141cc406Sopenharmony_ci dev->frontend = dev->frontend_initial; 1149141cc406Sopenharmony_ci 1150141cc406Sopenharmony_ci // reset only done on init 1151141cc406Sopenharmony_ci dev->interface->write_fe_register(0x04, 0x80); 1152141cc406Sopenharmony_ci 1153141cc406Sopenharmony_ci /* enable GPIO for some models */ 1154141cc406Sopenharmony_ci if (dev->model->sensor_id == SensorId::CCD_HP2300) { 1155141cc406Sopenharmony_ci val = 0x07; 1156141cc406Sopenharmony_ci gl646_gpio_output_enable(dev->interface->get_usb_device(), val); 1157141cc406Sopenharmony_ci } 1158141cc406Sopenharmony_ci return; 1159141cc406Sopenharmony_ci } 1160141cc406Sopenharmony_ci 1161141cc406Sopenharmony_ci // set fontend to power saving mode 1162141cc406Sopenharmony_ci if (set == AFE_POWER_SAVE) { 1163141cc406Sopenharmony_ci dev->interface->write_fe_register(0x01, 0x02); 1164141cc406Sopenharmony_ci return; 1165141cc406Sopenharmony_ci } 1166141cc406Sopenharmony_ci 1167141cc406Sopenharmony_ci /* here starts AFE_SET */ 1168141cc406Sopenharmony_ci /* TODO : base this test on cfg reg3 or a CCD family flag to be created */ 1169141cc406Sopenharmony_ci /* if (dev->model->ccd_type != SensorId::CCD_HP2300 1170141cc406Sopenharmony_ci && dev->model->ccd_type != SensorId::CCD_HP3670 1171141cc406Sopenharmony_ci && dev->model->ccd_type != SensorId::CCD_HP2400) */ 1172141cc406Sopenharmony_ci { 1173141cc406Sopenharmony_ci dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); 1174141cc406Sopenharmony_ci dev->interface->write_fe_register(0x02, dev->frontend.regs.get_value(0x02)); 1175141cc406Sopenharmony_ci } 1176141cc406Sopenharmony_ci 1177141cc406Sopenharmony_ci // start with reg3 1178141cc406Sopenharmony_ci dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x03)); 1179141cc406Sopenharmony_ci 1180141cc406Sopenharmony_ci switch (dev->model->sensor_id) 1181141cc406Sopenharmony_ci { 1182141cc406Sopenharmony_ci default: 1183141cc406Sopenharmony_ci for (i = 0; i < 3; i++) { 1184141cc406Sopenharmony_ci dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i)); 1185141cc406Sopenharmony_ci dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i)); 1186141cc406Sopenharmony_ci dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i)); 1187141cc406Sopenharmony_ci } 1188141cc406Sopenharmony_ci break; 1189141cc406Sopenharmony_ci /* just can't have it to work .... 1190141cc406Sopenharmony_ci case SensorId::CCD_HP2300: 1191141cc406Sopenharmony_ci case SensorId::CCD_HP2400: 1192141cc406Sopenharmony_ci case SensorId::CCD_HP3670: 1193141cc406Sopenharmony_ci 1194141cc406Sopenharmony_ci dev->interface->write_fe_register(0x23, dev->frontend.get_offset(1)); 1195141cc406Sopenharmony_ci dev->interface->write_fe_register(0x28, dev->frontend.get_gain(1)); 1196141cc406Sopenharmony_ci break; */ 1197141cc406Sopenharmony_ci } 1198141cc406Sopenharmony_ci 1199141cc406Sopenharmony_ci // end with reg1 1200141cc406Sopenharmony_ci dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); 1201141cc406Sopenharmony_ci} 1202141cc406Sopenharmony_ci 1203141cc406Sopenharmony_ci/** Set values of analog frontend 1204141cc406Sopenharmony_ci * this this the public interface, the gl646 as to use one more 1205141cc406Sopenharmony_ci * parameter to work effectively, hence the redirection 1206141cc406Sopenharmony_ci * @param dev device to set 1207141cc406Sopenharmony_ci * @param set action to execute 1208141cc406Sopenharmony_ci */ 1209141cc406Sopenharmony_civoid CommandSetGl646::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, 1210141cc406Sopenharmony_ci std::uint8_t set) const 1211141cc406Sopenharmony_ci{ 1212141cc406Sopenharmony_ci gl646_set_fe(dev, sensor, set, dev->settings.yres); 1213141cc406Sopenharmony_ci} 1214141cc406Sopenharmony_ci 1215141cc406Sopenharmony_ci/** 1216141cc406Sopenharmony_ci * enters or leaves power saving mode 1217141cc406Sopenharmony_ci * limited to AFE for now. 1218141cc406Sopenharmony_ci * @param dev scanner's device 1219141cc406Sopenharmony_ci * @param enable true to enable power saving, false to leave it 1220141cc406Sopenharmony_ci */ 1221141cc406Sopenharmony_civoid CommandSetGl646::save_power(Genesys_Device* dev, bool enable) const 1222141cc406Sopenharmony_ci{ 1223141cc406Sopenharmony_ci DBG_HELPER_ARGS(dbg, "enable = %d", enable); 1224141cc406Sopenharmony_ci 1225141cc406Sopenharmony_ci const auto& sensor = sanei_genesys_find_sensor_any(dev); 1226141cc406Sopenharmony_ci 1227141cc406Sopenharmony_ci if (enable) 1228141cc406Sopenharmony_ci { 1229141cc406Sopenharmony_ci // gl646_set_fe(dev, sensor, AFE_POWER_SAVE); 1230141cc406Sopenharmony_ci } 1231141cc406Sopenharmony_ci else 1232141cc406Sopenharmony_ci { 1233141cc406Sopenharmony_ci gl646_set_fe(dev, sensor, AFE_INIT, 0); 1234141cc406Sopenharmony_ci } 1235141cc406Sopenharmony_ci} 1236141cc406Sopenharmony_ci 1237141cc406Sopenharmony_civoid CommandSetGl646::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const 1238141cc406Sopenharmony_ci{ 1239141cc406Sopenharmony_ci DBG_HELPER_ARGS(dbg, "delay = %d", delay); 1240141cc406Sopenharmony_ci Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); 1241141cc406Sopenharmony_ci int rate, exposure_time, tgtime, time; 1242141cc406Sopenharmony_ci 1243141cc406Sopenharmony_ci local_reg.init_reg(0x01, dev->reg.get8(0x01)); // disable fastmode 1244141cc406Sopenharmony_ci local_reg.init_reg(0x03, dev->reg.get8(0x03)); // Lamp power control 1245141cc406Sopenharmony_ci local_reg.init_reg(0x05, dev->reg.get8(0x05) & ~REG_0x05_BASESEL); // 24 clocks/pixel 1246141cc406Sopenharmony_ci local_reg.init_reg(0x38, 0x00); // line period low 1247141cc406Sopenharmony_ci local_reg.init_reg(0x39, 0x00); //line period high 1248141cc406Sopenharmony_ci local_reg.init_reg(0x6c, 0x00); // period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE 1249141cc406Sopenharmony_ci 1250141cc406Sopenharmony_ci if (!delay) 1251141cc406Sopenharmony_ci local_reg.find_reg(0x03).value &= 0xf0; /* disable lampdog and set lamptime = 0 */ 1252141cc406Sopenharmony_ci else if (delay < 20) 1253141cc406Sopenharmony_ci local_reg.find_reg(0x03).value = (local_reg.get8(0x03) & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */ 1254141cc406Sopenharmony_ci else 1255141cc406Sopenharmony_ci local_reg.find_reg(0x03).value = (local_reg.get8(0x03) & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */ 1256141cc406Sopenharmony_ci 1257141cc406Sopenharmony_ci time = delay * 1000 * 60; /* -> msec */ 1258141cc406Sopenharmony_ci exposure_time = static_cast<std::uint32_t>((time * 32000.0 / 1259141cc406Sopenharmony_ci (24.0 * 64.0 * (local_reg.get8(0x03) & REG_0x03_LAMPTIM) * 1260141cc406Sopenharmony_ci 1024.0) + 0.5)); 1261141cc406Sopenharmony_ci /* 32000 = system clock, 24 = clocks per pixel */ 1262141cc406Sopenharmony_ci rate = (exposure_time + 65536) / 65536; 1263141cc406Sopenharmony_ci if (rate > 4) 1264141cc406Sopenharmony_ci { 1265141cc406Sopenharmony_ci rate = 8; 1266141cc406Sopenharmony_ci tgtime = 3; 1267141cc406Sopenharmony_ci } 1268141cc406Sopenharmony_ci else if (rate > 2) 1269141cc406Sopenharmony_ci { 1270141cc406Sopenharmony_ci rate = 4; 1271141cc406Sopenharmony_ci tgtime = 2; 1272141cc406Sopenharmony_ci } 1273141cc406Sopenharmony_ci else if (rate > 1) 1274141cc406Sopenharmony_ci { 1275141cc406Sopenharmony_ci rate = 2; 1276141cc406Sopenharmony_ci tgtime = 1; 1277141cc406Sopenharmony_ci } 1278141cc406Sopenharmony_ci else 1279141cc406Sopenharmony_ci { 1280141cc406Sopenharmony_ci rate = 1; 1281141cc406Sopenharmony_ci tgtime = 0; 1282141cc406Sopenharmony_ci } 1283141cc406Sopenharmony_ci 1284141cc406Sopenharmony_ci local_reg.find_reg(0x6c).value |= tgtime << 6; 1285141cc406Sopenharmony_ci exposure_time /= rate; 1286141cc406Sopenharmony_ci 1287141cc406Sopenharmony_ci if (exposure_time > 65535) 1288141cc406Sopenharmony_ci exposure_time = 65535; 1289141cc406Sopenharmony_ci 1290141cc406Sopenharmony_ci local_reg.find_reg(0x38).value = exposure_time / 256; 1291141cc406Sopenharmony_ci local_reg.find_reg(0x39).value = exposure_time & 255; 1292141cc406Sopenharmony_ci 1293141cc406Sopenharmony_ci dev->interface->write_registers(local_reg); 1294141cc406Sopenharmony_ci} 1295141cc406Sopenharmony_ci 1296141cc406Sopenharmony_ci 1297141cc406Sopenharmony_ci/** 1298141cc406Sopenharmony_ci * loads document into scanner 1299141cc406Sopenharmony_ci * currently only used by XP200 1300141cc406Sopenharmony_ci * bit2 (0x04) of gpio is paper event (document in/out) on XP200 1301141cc406Sopenharmony_ci * HOMESNR is set if no document in front of sensor, the sequence of events is 1302141cc406Sopenharmony_ci * paper event -> document is in the sheet feeder 1303141cc406Sopenharmony_ci * HOMESNR becomes 0 -> document reach sensor 1304141cc406Sopenharmony_ci * HOMESNR becomes 1 ->document left sensor 1305141cc406Sopenharmony_ci * paper event -> document is out 1306141cc406Sopenharmony_ci */ 1307141cc406Sopenharmony_civoid CommandSetGl646::load_document(Genesys_Device* dev) const 1308141cc406Sopenharmony_ci{ 1309141cc406Sopenharmony_ci DBG_HELPER(dbg); 1310141cc406Sopenharmony_ci 1311141cc406Sopenharmony_ci // FIXME: sequential not really needed in this case 1312141cc406Sopenharmony_ci Genesys_Register_Set regs(Genesys_Register_Set::SEQUENTIAL); 1313141cc406Sopenharmony_ci unsigned count; 1314141cc406Sopenharmony_ci 1315141cc406Sopenharmony_ci /* no need to load document is flatbed scanner */ 1316141cc406Sopenharmony_ci if (!dev->model->is_sheetfed) { 1317141cc406Sopenharmony_ci DBG(DBG_proc, "%s: nothing to load\n", __func__); 1318141cc406Sopenharmony_ci DBG(DBG_proc, "%s: end\n", __func__); 1319141cc406Sopenharmony_ci return; 1320141cc406Sopenharmony_ci } 1321141cc406Sopenharmony_ci 1322141cc406Sopenharmony_ci auto status = scanner_read_status(*dev); 1323141cc406Sopenharmony_ci 1324141cc406Sopenharmony_ci // home sensor is set if a document is inserted 1325141cc406Sopenharmony_ci if (status.is_at_home) { 1326141cc406Sopenharmony_ci /* if no document, waits for a paper event to start loading */ 1327141cc406Sopenharmony_ci /* with a 60 seconde minutes timeout */ 1328141cc406Sopenharmony_ci count = 0; 1329141cc406Sopenharmony_ci std::uint8_t val = 0; 1330141cc406Sopenharmony_ci do { 1331141cc406Sopenharmony_ci gl646_gpio_read(dev->interface->get_usb_device(), &val); 1332141cc406Sopenharmony_ci 1333141cc406Sopenharmony_ci DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, val); 1334141cc406Sopenharmony_ci if ((val & 0x04) != 0x04) 1335141cc406Sopenharmony_ci { 1336141cc406Sopenharmony_ci DBG(DBG_warn, "%s: no paper detected\n", __func__); 1337141cc406Sopenharmony_ci } 1338141cc406Sopenharmony_ci dev->interface->sleep_ms(200); 1339141cc406Sopenharmony_ci count++; 1340141cc406Sopenharmony_ci } 1341141cc406Sopenharmony_ci while (((val & 0x04) != 0x04) && (count < 300)); /* 1 min time out */ 1342141cc406Sopenharmony_ci if (count == 300) 1343141cc406Sopenharmony_ci { 1344141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_NO_DOCS, "timeout waiting for document"); 1345141cc406Sopenharmony_ci } 1346141cc406Sopenharmony_ci } 1347141cc406Sopenharmony_ci 1348141cc406Sopenharmony_ci /* set up to fast move before scan then move until document is detected */ 1349141cc406Sopenharmony_ci regs.init_reg(0x01, 0x90); 1350141cc406Sopenharmony_ci 1351141cc406Sopenharmony_ci /* AGOME, 2 slopes motor moving */ 1352141cc406Sopenharmony_ci regs.init_reg(0x02, 0x79); 1353141cc406Sopenharmony_ci 1354141cc406Sopenharmony_ci /* motor feeding steps to 0 */ 1355141cc406Sopenharmony_ci regs.init_reg(0x3d, 0); 1356141cc406Sopenharmony_ci regs.init_reg(0x3e, 0); 1357141cc406Sopenharmony_ci regs.init_reg(0x3f, 0); 1358141cc406Sopenharmony_ci 1359141cc406Sopenharmony_ci /* 50 fast moving steps */ 1360141cc406Sopenharmony_ci regs.init_reg(0x6b, 50); 1361141cc406Sopenharmony_ci 1362141cc406Sopenharmony_ci /* set GPO */ 1363141cc406Sopenharmony_ci regs.init_reg(0x66, 0x30); 1364141cc406Sopenharmony_ci 1365141cc406Sopenharmony_ci /* stesp NO */ 1366141cc406Sopenharmony_ci regs.init_reg(0x21, 4); 1367141cc406Sopenharmony_ci regs.init_reg(0x22, 1); 1368141cc406Sopenharmony_ci regs.init_reg(0x23, 1); 1369141cc406Sopenharmony_ci regs.init_reg(0x24, 4); 1370141cc406Sopenharmony_ci 1371141cc406Sopenharmony_ci /* generate slope table 2 */ 1372141cc406Sopenharmony_ci auto slope_table = create_slope_table_for_speed(MotorSlope::create_from_steps(6000, 2400, 50), 1373141cc406Sopenharmony_ci 2400, StepType::FULL, 1, 4, 1374141cc406Sopenharmony_ci get_slope_table_max_size(AsicType::GL646)); 1375141cc406Sopenharmony_ci // document loading: 1376141cc406Sopenharmony_ci // send regs 1377141cc406Sopenharmony_ci // start motor 1378141cc406Sopenharmony_ci // wait e1 status to become e0 1379141cc406Sopenharmony_ci const auto& sensor = sanei_genesys_find_sensor_any(dev); 1380141cc406Sopenharmony_ci scanner_send_slope_table(dev, sensor, 1, slope_table.table); 1381141cc406Sopenharmony_ci 1382141cc406Sopenharmony_ci dev->interface->write_registers(regs); 1383141cc406Sopenharmony_ci 1384141cc406Sopenharmony_ci scanner_start_action(*dev, true); 1385141cc406Sopenharmony_ci 1386141cc406Sopenharmony_ci count = 0; 1387141cc406Sopenharmony_ci do 1388141cc406Sopenharmony_ci { 1389141cc406Sopenharmony_ci status = scanner_read_status(*dev); 1390141cc406Sopenharmony_ci dev->interface->sleep_ms(200); 1391141cc406Sopenharmony_ci count++; 1392141cc406Sopenharmony_ci } while (status.is_motor_enabled && (count < 300)); 1393141cc406Sopenharmony_ci 1394141cc406Sopenharmony_ci if (count == 300) 1395141cc406Sopenharmony_ci { 1396141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_JAMMED, "can't load document"); 1397141cc406Sopenharmony_ci } 1398141cc406Sopenharmony_ci 1399141cc406Sopenharmony_ci /* when loading OK, document is here */ 1400141cc406Sopenharmony_ci dev->document = true; 1401141cc406Sopenharmony_ci 1402141cc406Sopenharmony_ci /* set up to idle */ 1403141cc406Sopenharmony_ci regs.set8(0x02, 0x71); 1404141cc406Sopenharmony_ci regs.set8(0x3f, 1); 1405141cc406Sopenharmony_ci regs.set8(0x6b, 8); 1406141cc406Sopenharmony_ci dev->interface->write_registers(regs); 1407141cc406Sopenharmony_ci} 1408141cc406Sopenharmony_ci 1409141cc406Sopenharmony_ci/** 1410141cc406Sopenharmony_ci * detects end of document and adjust current scan 1411141cc406Sopenharmony_ci * to take it into account 1412141cc406Sopenharmony_ci * used by sheetfed scanners 1413141cc406Sopenharmony_ci */ 1414141cc406Sopenharmony_civoid CommandSetGl646::detect_document_end(Genesys_Device* dev) const 1415141cc406Sopenharmony_ci{ 1416141cc406Sopenharmony_ci DBG_HELPER(dbg); 1417141cc406Sopenharmony_ci std::uint8_t gpio; 1418141cc406Sopenharmony_ci unsigned int bytes_left; 1419141cc406Sopenharmony_ci 1420141cc406Sopenharmony_ci // test for document presence 1421141cc406Sopenharmony_ci scanner_read_print_status(*dev); 1422141cc406Sopenharmony_ci 1423141cc406Sopenharmony_ci gl646_gpio_read(dev->interface->get_usb_device(), &gpio); 1424141cc406Sopenharmony_ci DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); 1425141cc406Sopenharmony_ci 1426141cc406Sopenharmony_ci /* detect document event. There one event when the document go in, 1427141cc406Sopenharmony_ci * then another when it leaves */ 1428141cc406Sopenharmony_ci if (dev->document && (gpio & 0x04) && (dev->total_bytes_read > 0)) { 1429141cc406Sopenharmony_ci DBG(DBG_info, "%s: no more document\n", __func__); 1430141cc406Sopenharmony_ci dev->document = false; 1431141cc406Sopenharmony_ci 1432141cc406Sopenharmony_ci /* adjust number of bytes to read: 1433141cc406Sopenharmony_ci * total_bytes_to_read is the number of byte to send to frontend 1434141cc406Sopenharmony_ci * total_bytes_read is the number of bytes sent to frontend 1435141cc406Sopenharmony_ci * read_bytes_left is the number of bytes to read from the scanner 1436141cc406Sopenharmony_ci */ 1437141cc406Sopenharmony_ci DBG(DBG_io, "%s: total_bytes_to_read=%zu\n", __func__, dev->total_bytes_to_read); 1438141cc406Sopenharmony_ci DBG(DBG_io, "%s: total_bytes_read =%zu\n", __func__, dev->total_bytes_read); 1439141cc406Sopenharmony_ci 1440141cc406Sopenharmony_ci // amount of data available from scanner is what to scan 1441141cc406Sopenharmony_ci sanei_genesys_read_valid_words(dev, &bytes_left); 1442141cc406Sopenharmony_ci 1443141cc406Sopenharmony_ci unsigned lines_in_buffer = bytes_left / dev->session.output_line_bytes_raw; 1444141cc406Sopenharmony_ci 1445141cc406Sopenharmony_ci // we add the number of lines needed to read the last part of the document in 1446141cc406Sopenharmony_ci unsigned lines_offset = static_cast<unsigned>( 1447141cc406Sopenharmony_ci (dev->model->y_offset * dev->session.params.yres) / MM_PER_INCH); 1448141cc406Sopenharmony_ci 1449141cc406Sopenharmony_ci unsigned remaining_lines = lines_in_buffer + lines_offset; 1450141cc406Sopenharmony_ci 1451141cc406Sopenharmony_ci bytes_left = remaining_lines * dev->session.output_line_bytes_raw; 1452141cc406Sopenharmony_ci 1453141cc406Sopenharmony_ci if (bytes_left < dev->get_pipeline_source().remaining_bytes()) { 1454141cc406Sopenharmony_ci dev->get_pipeline_source().set_remaining_bytes(bytes_left); 1455141cc406Sopenharmony_ci dev->total_bytes_to_read = dev->total_bytes_read + bytes_left; 1456141cc406Sopenharmony_ci } 1457141cc406Sopenharmony_ci DBG(DBG_io, "%s: total_bytes_to_read=%zu\n", __func__, dev->total_bytes_to_read); 1458141cc406Sopenharmony_ci DBG(DBG_io, "%s: total_bytes_read =%zu\n", __func__, dev->total_bytes_read); 1459141cc406Sopenharmony_ci } 1460141cc406Sopenharmony_ci} 1461141cc406Sopenharmony_ci 1462141cc406Sopenharmony_ci/** 1463141cc406Sopenharmony_ci * eject document from the feeder 1464141cc406Sopenharmony_ci * currently only used by XP200 1465141cc406Sopenharmony_ci * TODO we currently rely on AGOHOME not being set for sheetfed scanners, 1466141cc406Sopenharmony_ci * maybe check this flag in eject to let the document being eject automatically 1467141cc406Sopenharmony_ci */ 1468141cc406Sopenharmony_civoid CommandSetGl646::eject_document(Genesys_Device* dev) const 1469141cc406Sopenharmony_ci{ 1470141cc406Sopenharmony_ci DBG_HELPER(dbg); 1471141cc406Sopenharmony_ci 1472141cc406Sopenharmony_ci // FIXME: SEQUENTIAL not really needed in this case 1473141cc406Sopenharmony_ci Genesys_Register_Set regs((Genesys_Register_Set::SEQUENTIAL)); 1474141cc406Sopenharmony_ci unsigned count; 1475141cc406Sopenharmony_ci std::uint8_t gpio; 1476141cc406Sopenharmony_ci 1477141cc406Sopenharmony_ci /* at the end there will be no more document */ 1478141cc406Sopenharmony_ci dev->document = false; 1479141cc406Sopenharmony_ci 1480141cc406Sopenharmony_ci // first check for document event 1481141cc406Sopenharmony_ci gl646_gpio_read(dev->interface->get_usb_device(), &gpio); 1482141cc406Sopenharmony_ci 1483141cc406Sopenharmony_ci DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); 1484141cc406Sopenharmony_ci 1485141cc406Sopenharmony_ci // test status : paper event + HOMESNR -> no more doc ? 1486141cc406Sopenharmony_ci auto status = scanner_read_status(*dev); 1487141cc406Sopenharmony_ci 1488141cc406Sopenharmony_ci // home sensor is set when document is inserted 1489141cc406Sopenharmony_ci if (status.is_at_home) { 1490141cc406Sopenharmony_ci dev->document = false; 1491141cc406Sopenharmony_ci DBG(DBG_info, "%s: no more document to eject\n", __func__); 1492141cc406Sopenharmony_ci return; 1493141cc406Sopenharmony_ci } 1494141cc406Sopenharmony_ci 1495141cc406Sopenharmony_ci // there is a document inserted, eject it 1496141cc406Sopenharmony_ci dev->interface->write_register(0x01, 0xb0); 1497141cc406Sopenharmony_ci 1498141cc406Sopenharmony_ci /* wait for motor to stop */ 1499141cc406Sopenharmony_ci do { 1500141cc406Sopenharmony_ci dev->interface->sleep_ms(200); 1501141cc406Sopenharmony_ci status = scanner_read_status(*dev); 1502141cc406Sopenharmony_ci } 1503141cc406Sopenharmony_ci while (status.is_motor_enabled); 1504141cc406Sopenharmony_ci 1505141cc406Sopenharmony_ci /* set up to fast move before scan then move until document is detected */ 1506141cc406Sopenharmony_ci regs.init_reg(0x01, 0xb0); 1507141cc406Sopenharmony_ci 1508141cc406Sopenharmony_ci /* AGOME, 2 slopes motor moving , eject 'backward' */ 1509141cc406Sopenharmony_ci regs.init_reg(0x02, 0x5d); 1510141cc406Sopenharmony_ci 1511141cc406Sopenharmony_ci /* motor feeding steps to 119880 */ 1512141cc406Sopenharmony_ci regs.init_reg(0x3d, 1); 1513141cc406Sopenharmony_ci regs.init_reg(0x3e, 0xd4); 1514141cc406Sopenharmony_ci regs.init_reg(0x3f, 0x48); 1515141cc406Sopenharmony_ci 1516141cc406Sopenharmony_ci /* 60 fast moving steps */ 1517141cc406Sopenharmony_ci regs.init_reg(0x6b, 60); 1518141cc406Sopenharmony_ci 1519141cc406Sopenharmony_ci /* set GPO */ 1520141cc406Sopenharmony_ci regs.init_reg(0x66, 0x30); 1521141cc406Sopenharmony_ci 1522141cc406Sopenharmony_ci /* stesp NO */ 1523141cc406Sopenharmony_ci regs.init_reg(0x21, 4); 1524141cc406Sopenharmony_ci regs.init_reg(0x22, 1); 1525141cc406Sopenharmony_ci regs.init_reg(0x23, 1); 1526141cc406Sopenharmony_ci regs.init_reg(0x24, 4); 1527141cc406Sopenharmony_ci 1528141cc406Sopenharmony_ci /* generate slope table 2 */ 1529141cc406Sopenharmony_ci auto slope_table = create_slope_table_for_speed(MotorSlope::create_from_steps(10000, 1600, 60), 1530141cc406Sopenharmony_ci 1600, StepType::FULL, 1, 4, 1531141cc406Sopenharmony_ci get_slope_table_max_size(AsicType::GL646)); 1532141cc406Sopenharmony_ci // document eject: 1533141cc406Sopenharmony_ci // send regs 1534141cc406Sopenharmony_ci // start motor 1535141cc406Sopenharmony_ci // wait c1 status to become c8 : HOMESNR and ~MOTFLAG 1536141cc406Sopenharmony_ci // FIXME: sensor is not used. 1537141cc406Sopenharmony_ci const auto& sensor = sanei_genesys_find_sensor_any(dev); 1538141cc406Sopenharmony_ci scanner_send_slope_table(dev, sensor, 1, slope_table.table); 1539141cc406Sopenharmony_ci 1540141cc406Sopenharmony_ci dev->interface->write_registers(regs); 1541141cc406Sopenharmony_ci 1542141cc406Sopenharmony_ci scanner_start_action(*dev, true); 1543141cc406Sopenharmony_ci 1544141cc406Sopenharmony_ci /* loop until paper sensor tells paper is out, and till motor is running */ 1545141cc406Sopenharmony_ci /* use a 30 timeout */ 1546141cc406Sopenharmony_ci count = 0; 1547141cc406Sopenharmony_ci do { 1548141cc406Sopenharmony_ci status = scanner_read_status(*dev); 1549141cc406Sopenharmony_ci 1550141cc406Sopenharmony_ci dev->interface->sleep_ms(200); 1551141cc406Sopenharmony_ci count++; 1552141cc406Sopenharmony_ci } while (!status.is_at_home && (count < 150)); 1553141cc406Sopenharmony_ci 1554141cc406Sopenharmony_ci // read GPIO on exit 1555141cc406Sopenharmony_ci gl646_gpio_read(dev->interface->get_usb_device(), &gpio); 1556141cc406Sopenharmony_ci 1557141cc406Sopenharmony_ci DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); 1558141cc406Sopenharmony_ci} 1559141cc406Sopenharmony_ci 1560141cc406Sopenharmony_ci// Send the low-level scan command 1561141cc406Sopenharmony_civoid CommandSetGl646::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, 1562141cc406Sopenharmony_ci Genesys_Register_Set* reg, bool start_motor) const 1563141cc406Sopenharmony_ci{ 1564141cc406Sopenharmony_ci DBG_HELPER(dbg); 1565141cc406Sopenharmony_ci (void) sensor; 1566141cc406Sopenharmony_ci // FIXME: SEQUENTIAL not really needed in this case 1567141cc406Sopenharmony_ci Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); 1568141cc406Sopenharmony_ci 1569141cc406Sopenharmony_ci local_reg.init_reg(0x03, reg->get8(0x03)); 1570141cc406Sopenharmony_ci local_reg.init_reg(0x01, reg->get8(0x01) | REG_0x01_SCAN); 1571141cc406Sopenharmony_ci 1572141cc406Sopenharmony_ci if (start_motor) { 1573141cc406Sopenharmony_ci local_reg.init_reg(0x0f, 0x01); 1574141cc406Sopenharmony_ci } else { 1575141cc406Sopenharmony_ci local_reg.init_reg(0x0f, 0x00); // do not start motor yet 1576141cc406Sopenharmony_ci } 1577141cc406Sopenharmony_ci 1578141cc406Sopenharmony_ci dev->interface->write_registers(local_reg); 1579141cc406Sopenharmony_ci 1580141cc406Sopenharmony_ci dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); 1581141cc406Sopenharmony_ci} 1582141cc406Sopenharmony_ci 1583141cc406Sopenharmony_ci 1584141cc406Sopenharmony_ci// Send the stop scan command 1585141cc406Sopenharmony_cistatic void end_scan_impl(Genesys_Device* dev, Genesys_Register_Set* reg, bool check_stop, 1586141cc406Sopenharmony_ci bool eject) 1587141cc406Sopenharmony_ci{ 1588141cc406Sopenharmony_ci DBG_HELPER_ARGS(dbg, "check_stop = %d, eject = %d", check_stop, eject); 1589141cc406Sopenharmony_ci 1590141cc406Sopenharmony_ci scanner_stop_action_no_move(*dev, *reg); 1591141cc406Sopenharmony_ci 1592141cc406Sopenharmony_ci unsigned wait_limit_seconds = 30; 1593141cc406Sopenharmony_ci 1594141cc406Sopenharmony_ci /* for sheetfed scanners, we may have to eject document */ 1595141cc406Sopenharmony_ci if (dev->model->is_sheetfed) { 1596141cc406Sopenharmony_ci if (eject && dev->document) { 1597141cc406Sopenharmony_ci dev->cmd_set->eject_document(dev); 1598141cc406Sopenharmony_ci } 1599141cc406Sopenharmony_ci wait_limit_seconds = 3; 1600141cc406Sopenharmony_ci } 1601141cc406Sopenharmony_ci 1602141cc406Sopenharmony_ci if (is_testing_mode()) { 1603141cc406Sopenharmony_ci return; 1604141cc406Sopenharmony_ci } 1605141cc406Sopenharmony_ci 1606141cc406Sopenharmony_ci dev->interface->sleep_ms(100); 1607141cc406Sopenharmony_ci 1608141cc406Sopenharmony_ci if (check_stop) { 1609141cc406Sopenharmony_ci for (unsigned i = 0; i < wait_limit_seconds * 10; i++) { 1610141cc406Sopenharmony_ci if (scanner_is_motor_stopped(*dev)) { 1611141cc406Sopenharmony_ci return; 1612141cc406Sopenharmony_ci } 1613141cc406Sopenharmony_ci 1614141cc406Sopenharmony_ci dev->interface->sleep_ms(100); 1615141cc406Sopenharmony_ci } 1616141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_IO_ERROR, "could not stop motor"); 1617141cc406Sopenharmony_ci } 1618141cc406Sopenharmony_ci} 1619141cc406Sopenharmony_ci 1620141cc406Sopenharmony_ci// Send the stop scan command 1621141cc406Sopenharmony_civoid CommandSetGl646::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg, 1622141cc406Sopenharmony_ci bool check_stop) const 1623141cc406Sopenharmony_ci{ 1624141cc406Sopenharmony_ci end_scan_impl(dev, reg, check_stop, false); 1625141cc406Sopenharmony_ci} 1626141cc406Sopenharmony_ci 1627141cc406Sopenharmony_ci/** 1628141cc406Sopenharmony_ci * parks head 1629141cc406Sopenharmony_ci * @param dev scanner's device 1630141cc406Sopenharmony_ci * @param wait_until_home true if the function waits until head parked 1631141cc406Sopenharmony_ci */ 1632141cc406Sopenharmony_civoid CommandSetGl646::move_back_home(Genesys_Device* dev, bool wait_until_home) const 1633141cc406Sopenharmony_ci{ 1634141cc406Sopenharmony_ci DBG_HELPER_ARGS(dbg, "wait_until_home = %d\n", wait_until_home); 1635141cc406Sopenharmony_ci int i; 1636141cc406Sopenharmony_ci int loop = 0; 1637141cc406Sopenharmony_ci 1638141cc406Sopenharmony_ci auto status = scanner_read_status(*dev); 1639141cc406Sopenharmony_ci 1640141cc406Sopenharmony_ci if (status.is_at_home) { 1641141cc406Sopenharmony_ci DBG(DBG_info, "%s: end since already at home\n", __func__); 1642141cc406Sopenharmony_ci dev->set_head_pos_zero(ScanHeadId::PRIMARY); 1643141cc406Sopenharmony_ci return; 1644141cc406Sopenharmony_ci } 1645141cc406Sopenharmony_ci 1646141cc406Sopenharmony_ci /* stop motor if needed */ 1647141cc406Sopenharmony_ci if (status.is_motor_enabled) { 1648141cc406Sopenharmony_ci gl646_stop_motor(dev); 1649141cc406Sopenharmony_ci dev->interface->sleep_ms(200); 1650141cc406Sopenharmony_ci } 1651141cc406Sopenharmony_ci 1652141cc406Sopenharmony_ci /* when scanhead is moving then wait until scanhead stops or timeout */ 1653141cc406Sopenharmony_ci DBG(DBG_info, "%s: ensuring that motor is off\n", __func__); 1654141cc406Sopenharmony_ci for (i = 400; i > 0; i--) { 1655141cc406Sopenharmony_ci // do not wait longer than 40 seconds, count down to get i = 0 when busy 1656141cc406Sopenharmony_ci 1657141cc406Sopenharmony_ci status = scanner_read_status(*dev); 1658141cc406Sopenharmony_ci 1659141cc406Sopenharmony_ci if (!status.is_motor_enabled && status.is_at_home) { 1660141cc406Sopenharmony_ci DBG(DBG_info, "%s: already at home and not moving\n", __func__); 1661141cc406Sopenharmony_ci dev->set_head_pos_zero(ScanHeadId::PRIMARY); 1662141cc406Sopenharmony_ci return; 1663141cc406Sopenharmony_ci } 1664141cc406Sopenharmony_ci if (!status.is_motor_enabled) { 1665141cc406Sopenharmony_ci break; 1666141cc406Sopenharmony_ci } 1667141cc406Sopenharmony_ci 1668141cc406Sopenharmony_ci dev->interface->sleep_ms(100); 1669141cc406Sopenharmony_ci } 1670141cc406Sopenharmony_ci 1671141cc406Sopenharmony_ci if (!i) /* the loop counted down to 0, scanner still is busy */ 1672141cc406Sopenharmony_ci { 1673141cc406Sopenharmony_ci dev->set_head_pos_unknown(ScanHeadId::PRIMARY | ScanHeadId::SECONDARY); 1674141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_DEVICE_BUSY, "motor is still on: device busy"); 1675141cc406Sopenharmony_ci } 1676141cc406Sopenharmony_ci 1677141cc406Sopenharmony_ci // setup for a backward scan of 65535 steps, with no actual data reading 1678141cc406Sopenharmony_ci auto resolution = sanei_genesys_get_lowest_dpi(dev); 1679141cc406Sopenharmony_ci 1680141cc406Sopenharmony_ci const auto& sensor = sanei_genesys_find_sensor(dev, resolution, 3, 1681141cc406Sopenharmony_ci dev->model->default_method); 1682141cc406Sopenharmony_ci 1683141cc406Sopenharmony_ci ScanSession session; 1684141cc406Sopenharmony_ci session.params.xres = resolution; 1685141cc406Sopenharmony_ci session.params.yres = resolution; 1686141cc406Sopenharmony_ci session.params.startx = 0; 1687141cc406Sopenharmony_ci session.params.starty = 65535; 1688141cc406Sopenharmony_ci session.params.pixels = 600; 1689141cc406Sopenharmony_ci session.params.lines = 1; 1690141cc406Sopenharmony_ci session.params.depth = 8; 1691141cc406Sopenharmony_ci session.params.channels = 3; 1692141cc406Sopenharmony_ci session.params.scan_method = dev->model->default_method; 1693141cc406Sopenharmony_ci session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; 1694141cc406Sopenharmony_ci session.params.color_filter = ColorFilter::RED; 1695141cc406Sopenharmony_ci session.params.contrast_adjustment = dev->settings.contrast; 1696141cc406Sopenharmony_ci session.params.brightness_adjustment = dev->settings.brightness; 1697141cc406Sopenharmony_ci session.params.flags = ScanFlag::REVERSE | 1698141cc406Sopenharmony_ci ScanFlag::AUTO_GO_HOME | 1699141cc406Sopenharmony_ci ScanFlag::DISABLE_GAMMA; 1700141cc406Sopenharmony_ci if (dev->model->default_method == ScanMethod::TRANSPARENCY) { 1701141cc406Sopenharmony_ci session.params.flags |= ScanFlag::USE_XPA; 1702141cc406Sopenharmony_ci } 1703141cc406Sopenharmony_ci compute_session(dev, session, sensor); 1704141cc406Sopenharmony_ci 1705141cc406Sopenharmony_ci init_regs_for_scan_session(dev, sensor, &dev->reg, session); 1706141cc406Sopenharmony_ci 1707141cc406Sopenharmony_ci /* backward , no actual data scanned TODO more setup flags to avoid this register manipulations ? */ 1708141cc406Sopenharmony_ci regs_set_optical_off(dev->model->asic_type, dev->reg); 1709141cc406Sopenharmony_ci 1710141cc406Sopenharmony_ci // sets frontend 1711141cc406Sopenharmony_ci gl646_set_fe(dev, sensor, AFE_SET, resolution); 1712141cc406Sopenharmony_ci 1713141cc406Sopenharmony_ci /* write scan registers */ 1714141cc406Sopenharmony_ci try { 1715141cc406Sopenharmony_ci dev->interface->write_registers(dev->reg); 1716141cc406Sopenharmony_ci } catch (...) { 1717141cc406Sopenharmony_ci DBG(DBG_error, "%s: failed to bulk write registers\n", __func__); 1718141cc406Sopenharmony_ci } 1719141cc406Sopenharmony_ci 1720141cc406Sopenharmony_ci /* registers are restored to an iddl state, give up if no head to park */ 1721141cc406Sopenharmony_ci if (dev->model->is_sheetfed) { 1722141cc406Sopenharmony_ci return; 1723141cc406Sopenharmony_ci } 1724141cc406Sopenharmony_ci 1725141cc406Sopenharmony_ci // starts scan 1726141cc406Sopenharmony_ci { 1727141cc406Sopenharmony_ci // this is effectively the same as dev->cmd_set->begin_scan(dev, sensor, &dev->reg, true); 1728141cc406Sopenharmony_ci // except that we don't modify the head position calculations 1729141cc406Sopenharmony_ci 1730141cc406Sopenharmony_ci // FIXME: SEQUENTIAL not really needed in this case 1731141cc406Sopenharmony_ci Genesys_Register_Set scan_local_reg(Genesys_Register_Set::SEQUENTIAL); 1732141cc406Sopenharmony_ci 1733141cc406Sopenharmony_ci scan_local_reg.init_reg(0x03, dev->reg.get8(0x03)); 1734141cc406Sopenharmony_ci scan_local_reg.init_reg(0x01, dev->reg.get8(0x01) | REG_0x01_SCAN); 1735141cc406Sopenharmony_ci scan_local_reg.init_reg(0x0f, 0x01); 1736141cc406Sopenharmony_ci 1737141cc406Sopenharmony_ci dev->interface->write_registers(scan_local_reg); 1738141cc406Sopenharmony_ci } 1739141cc406Sopenharmony_ci 1740141cc406Sopenharmony_ci if (is_testing_mode()) { 1741141cc406Sopenharmony_ci dev->interface->test_checkpoint("move_back_home"); 1742141cc406Sopenharmony_ci dev->set_head_pos_zero(ScanHeadId::PRIMARY); 1743141cc406Sopenharmony_ci return; 1744141cc406Sopenharmony_ci } 1745141cc406Sopenharmony_ci 1746141cc406Sopenharmony_ci /* loop until head parked */ 1747141cc406Sopenharmony_ci if (wait_until_home) 1748141cc406Sopenharmony_ci { 1749141cc406Sopenharmony_ci while (loop < 300) /* do not wait longer then 30 seconds */ 1750141cc406Sopenharmony_ci { 1751141cc406Sopenharmony_ci auto status = scanner_read_status(*dev); 1752141cc406Sopenharmony_ci 1753141cc406Sopenharmony_ci if (status.is_at_home) { 1754141cc406Sopenharmony_ci DBG(DBG_info, "%s: reached home position\n", __func__); 1755141cc406Sopenharmony_ci dev->interface->sleep_ms(500); 1756141cc406Sopenharmony_ci dev->set_head_pos_zero(ScanHeadId::PRIMARY); 1757141cc406Sopenharmony_ci return; 1758141cc406Sopenharmony_ci } 1759141cc406Sopenharmony_ci dev->interface->sleep_ms(100); 1760141cc406Sopenharmony_ci ++loop; 1761141cc406Sopenharmony_ci } 1762141cc406Sopenharmony_ci 1763141cc406Sopenharmony_ci // when we come here then the scanner needed too much time for this, so we better 1764141cc406Sopenharmony_ci // stop the motor 1765141cc406Sopenharmony_ci catch_all_exceptions(__func__, [&](){ gl646_stop_motor (dev); }); 1766141cc406Sopenharmony_ci catch_all_exceptions(__func__, [&](){ end_scan_impl(dev, &dev->reg, true, false); }); 1767141cc406Sopenharmony_ci dev->set_head_pos_unknown(ScanHeadId::PRIMARY | ScanHeadId::SECONDARY); 1768141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home"); 1769141cc406Sopenharmony_ci } 1770141cc406Sopenharmony_ci 1771141cc406Sopenharmony_ci 1772141cc406Sopenharmony_ci DBG(DBG_info, "%s: scanhead is still moving\n", __func__); 1773141cc406Sopenharmony_ci} 1774141cc406Sopenharmony_ci 1775141cc406Sopenharmony_ci/** 1776141cc406Sopenharmony_ci * init registers for shading calibration 1777141cc406Sopenharmony_ci * we assume that scanner's head is on an area suiting shading calibration. 1778141cc406Sopenharmony_ci * We scan a full scan width area by the shading line number for the device 1779141cc406Sopenharmony_ci */ 1780141cc406Sopenharmony_civoid CommandSetGl646::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, 1781141cc406Sopenharmony_ci Genesys_Register_Set& regs) const 1782141cc406Sopenharmony_ci{ 1783141cc406Sopenharmony_ci DBG_HELPER(dbg); 1784141cc406Sopenharmony_ci (void) regs; 1785141cc406Sopenharmony_ci 1786141cc406Sopenharmony_ci /* fill settings for scan : always a color scan */ 1787141cc406Sopenharmony_ci int channels = 3; 1788141cc406Sopenharmony_ci 1789141cc406Sopenharmony_ci unsigned cksel = get_cksel(dev->model->sensor_id, dev->settings.xres, channels); 1790141cc406Sopenharmony_ci 1791141cc406Sopenharmony_ci unsigned resolution = sensor.get_optical_resolution() / cksel; 1792141cc406Sopenharmony_ci // FIXME: we select wrong calibration sensor 1793141cc406Sopenharmony_ci const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->settings.xres, channels, 1794141cc406Sopenharmony_ci dev->settings.scan_method); 1795141cc406Sopenharmony_ci 1796141cc406Sopenharmony_ci auto pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH; 1797141cc406Sopenharmony_ci 1798141cc406Sopenharmony_ci unsigned calib_lines = 1799141cc406Sopenharmony_ci static_cast<unsigned>(dev->model->y_size_calib_mm * resolution / MM_PER_INCH); 1800141cc406Sopenharmony_ci 1801141cc406Sopenharmony_ci ScanSession session; 1802141cc406Sopenharmony_ci session.params.xres = resolution; 1803141cc406Sopenharmony_ci session.params.yres = resolution; 1804141cc406Sopenharmony_ci session.params.startx = 0; 1805141cc406Sopenharmony_ci session.params.starty = 0; 1806141cc406Sopenharmony_ci session.params.pixels = pixels; 1807141cc406Sopenharmony_ci session.params.lines = calib_lines; 1808141cc406Sopenharmony_ci session.params.depth = 16; 1809141cc406Sopenharmony_ci session.params.channels = channels; 1810141cc406Sopenharmony_ci session.params.scan_method = dev->settings.scan_method; 1811141cc406Sopenharmony_ci session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; 1812141cc406Sopenharmony_ci session.params.color_filter = dev->settings.color_filter; 1813141cc406Sopenharmony_ci session.params.contrast_adjustment = dev->settings.contrast; 1814141cc406Sopenharmony_ci session.params.brightness_adjustment = dev->settings.brightness; 1815141cc406Sopenharmony_ci session.params.flags = ScanFlag::DISABLE_SHADING | 1816141cc406Sopenharmony_ci ScanFlag::DISABLE_GAMMA | 1817141cc406Sopenharmony_ci ScanFlag::IGNORE_COLOR_OFFSET | 1818141cc406Sopenharmony_ci ScanFlag::IGNORE_STAGGER_OFFSET; 1819141cc406Sopenharmony_ci if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { 1820141cc406Sopenharmony_ci session.params.flags |= ScanFlag::USE_XPA; 1821141cc406Sopenharmony_ci } 1822141cc406Sopenharmony_ci compute_session(dev, session, calib_sensor); 1823141cc406Sopenharmony_ci 1824141cc406Sopenharmony_ci dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session); 1825141cc406Sopenharmony_ci 1826141cc406Sopenharmony_ci dev->calib_session = session; 1827141cc406Sopenharmony_ci 1828141cc406Sopenharmony_ci /* no shading */ 1829141cc406Sopenharmony_ci dev->reg.find_reg(0x02).value |= REG_0x02_ACDCDIS; /* ease backtracking */ 1830141cc406Sopenharmony_ci dev->reg.find_reg(0x02).value &= ~REG_0x02_FASTFED; 1831141cc406Sopenharmony_ci sanei_genesys_set_motor_power(dev->reg, false); 1832141cc406Sopenharmony_ci} 1833141cc406Sopenharmony_ci 1834141cc406Sopenharmony_cibool CommandSetGl646::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const 1835141cc406Sopenharmony_ci{ 1836141cc406Sopenharmony_ci return dev->is_head_pos_known(ScanHeadId::PRIMARY) && 1837141cc406Sopenharmony_ci dev->head_pos(ScanHeadId::PRIMARY) && 1838141cc406Sopenharmony_ci dev->settings.scan_method == ScanMethod::FLATBED; 1839141cc406Sopenharmony_ci} 1840141cc406Sopenharmony_ci 1841141cc406Sopenharmony_ci/** 1842141cc406Sopenharmony_ci * this function send gamma table to ASIC 1843141cc406Sopenharmony_ci */ 1844141cc406Sopenharmony_civoid CommandSetGl646::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const 1845141cc406Sopenharmony_ci{ 1846141cc406Sopenharmony_ci DBG_HELPER(dbg); 1847141cc406Sopenharmony_ci int size; 1848141cc406Sopenharmony_ci int address; 1849141cc406Sopenharmony_ci int bits; 1850141cc406Sopenharmony_ci 1851141cc406Sopenharmony_ci if (has_flag(dev->model->flags, ModelFlag::GAMMA_14BIT)) { 1852141cc406Sopenharmony_ci size = 16384; 1853141cc406Sopenharmony_ci bits = 14; 1854141cc406Sopenharmony_ci } 1855141cc406Sopenharmony_ci else 1856141cc406Sopenharmony_ci { 1857141cc406Sopenharmony_ci size = 4096; 1858141cc406Sopenharmony_ci bits = 12; 1859141cc406Sopenharmony_ci } 1860141cc406Sopenharmony_ci 1861141cc406Sopenharmony_ci auto gamma = generate_gamma_buffer(dev, sensor, bits, size-1, size); 1862141cc406Sopenharmony_ci 1863141cc406Sopenharmony_ci /* table address */ 1864141cc406Sopenharmony_ci switch (dev->reg.find_reg(0x05).value >> 6) 1865141cc406Sopenharmony_ci { 1866141cc406Sopenharmony_ci case 0: /* 600 dpi */ 1867141cc406Sopenharmony_ci address = 0x09000; 1868141cc406Sopenharmony_ci break; 1869141cc406Sopenharmony_ci case 1: /* 1200 dpi */ 1870141cc406Sopenharmony_ci address = 0x11000; 1871141cc406Sopenharmony_ci break; 1872141cc406Sopenharmony_ci case 2: /* 2400 dpi */ 1873141cc406Sopenharmony_ci address = 0x20000; 1874141cc406Sopenharmony_ci break; 1875141cc406Sopenharmony_ci default: 1876141cc406Sopenharmony_ci throw SaneException("invalid dpi"); 1877141cc406Sopenharmony_ci } 1878141cc406Sopenharmony_ci 1879141cc406Sopenharmony_ci dev->interface->write_buffer(0x3c, address, gamma.data(), size * 2 * 3); 1880141cc406Sopenharmony_ci} 1881141cc406Sopenharmony_ci 1882141cc406Sopenharmony_ci/** @brief this function does the led calibration. 1883141cc406Sopenharmony_ci * this function does the led calibration by scanning one line of the calibration 1884141cc406Sopenharmony_ci * area below scanner's top on white strip. The scope of this function is 1885141cc406Sopenharmony_ci * currently limited to the XP200 1886141cc406Sopenharmony_ci */ 1887141cc406Sopenharmony_ciSensorExposure CommandSetGl646::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, 1888141cc406Sopenharmony_ci Genesys_Register_Set& regs) const 1889141cc406Sopenharmony_ci{ 1890141cc406Sopenharmony_ci DBG_HELPER(dbg); 1891141cc406Sopenharmony_ci (void) regs; 1892141cc406Sopenharmony_ci unsigned int i, j; 1893141cc406Sopenharmony_ci int val; 1894141cc406Sopenharmony_ci int avg[3], avga, avge; 1895141cc406Sopenharmony_ci int turn; 1896141cc406Sopenharmony_ci std::uint16_t expr, expg, expb; 1897141cc406Sopenharmony_ci 1898141cc406Sopenharmony_ci unsigned channels = dev->settings.get_channels(); 1899141cc406Sopenharmony_ci 1900141cc406Sopenharmony_ci ScanColorMode scan_mode = ScanColorMode::COLOR_SINGLE_PASS; 1901141cc406Sopenharmony_ci if (dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS) { 1902141cc406Sopenharmony_ci scan_mode = ScanColorMode::GRAY; 1903141cc406Sopenharmony_ci } 1904141cc406Sopenharmony_ci 1905141cc406Sopenharmony_ci // offset calibration is always done in color mode 1906141cc406Sopenharmony_ci unsigned pixels = dev->model->x_size_calib_mm * sensor.full_resolution / MM_PER_INCH; 1907141cc406Sopenharmony_ci 1908141cc406Sopenharmony_ci ScanSession session; 1909141cc406Sopenharmony_ci session.params.xres = sensor.full_resolution; 1910141cc406Sopenharmony_ci session.params.yres = sensor.full_resolution; 1911141cc406Sopenharmony_ci session.params.startx = 0; 1912141cc406Sopenharmony_ci session.params.starty = 0; 1913141cc406Sopenharmony_ci session.params.pixels = pixels; 1914141cc406Sopenharmony_ci session.params.lines = 1; 1915141cc406Sopenharmony_ci session.params.depth = 16; 1916141cc406Sopenharmony_ci session.params.channels = channels; 1917141cc406Sopenharmony_ci session.params.scan_method = dev->settings.scan_method; 1918141cc406Sopenharmony_ci session.params.scan_mode = scan_mode; 1919141cc406Sopenharmony_ci session.params.color_filter = ColorFilter::RED; 1920141cc406Sopenharmony_ci session.params.contrast_adjustment = dev->settings.contrast; 1921141cc406Sopenharmony_ci session.params.brightness_adjustment = dev->settings.brightness; 1922141cc406Sopenharmony_ci session.params.flags = ScanFlag::DISABLE_SHADING; 1923141cc406Sopenharmony_ci if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { 1924141cc406Sopenharmony_ci session.params.flags |= ScanFlag::USE_XPA; 1925141cc406Sopenharmony_ci } 1926141cc406Sopenharmony_ci compute_session(dev, session, sensor); 1927141cc406Sopenharmony_ci 1928141cc406Sopenharmony_ci // colors * bytes_per_color * scan lines 1929141cc406Sopenharmony_ci unsigned total_size = pixels * channels * 2 * 1; 1930141cc406Sopenharmony_ci 1931141cc406Sopenharmony_ci std::vector<std::uint8_t> line(total_size); 1932141cc406Sopenharmony_ci 1933141cc406Sopenharmony_ci/* 1934141cc406Sopenharmony_ci we try to get equal bright leds here: 1935141cc406Sopenharmony_ci 1936141cc406Sopenharmony_ci loop: 1937141cc406Sopenharmony_ci average per color 1938141cc406Sopenharmony_ci adjust exposure times 1939141cc406Sopenharmony_ci */ 1940141cc406Sopenharmony_ci expr = sensor.exposure.red; 1941141cc406Sopenharmony_ci expg = sensor.exposure.green; 1942141cc406Sopenharmony_ci expb = sensor.exposure.blue; 1943141cc406Sopenharmony_ci 1944141cc406Sopenharmony_ci turn = 0; 1945141cc406Sopenharmony_ci 1946141cc406Sopenharmony_ci auto calib_sensor = sensor; 1947141cc406Sopenharmony_ci 1948141cc406Sopenharmony_ci bool acceptable = false; 1949141cc406Sopenharmony_ci do { 1950141cc406Sopenharmony_ci calib_sensor.exposure.red = expr; 1951141cc406Sopenharmony_ci calib_sensor.exposure.green = expg; 1952141cc406Sopenharmony_ci calib_sensor.exposure.blue = expb; 1953141cc406Sopenharmony_ci 1954141cc406Sopenharmony_ci DBG(DBG_info, "%s: starting first line reading\n", __func__); 1955141cc406Sopenharmony_ci 1956141cc406Sopenharmony_ci dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session); 1957141cc406Sopenharmony_ci simple_scan(dev, calib_sensor, session, false, line, "led_calibration"); 1958141cc406Sopenharmony_ci 1959141cc406Sopenharmony_ci if (is_testing_mode()) { 1960141cc406Sopenharmony_ci return calib_sensor.exposure; 1961141cc406Sopenharmony_ci } 1962141cc406Sopenharmony_ci 1963141cc406Sopenharmony_ci if (dbg_log_image_data()) { 1964141cc406Sopenharmony_ci char fn[30]; 1965141cc406Sopenharmony_ci std::snprintf(fn, 30, "gl646_led_%02d.tiff", turn); 1966141cc406Sopenharmony_ci write_tiff_file(fn, line.data(), 16, channels, pixels, 1); 1967141cc406Sopenharmony_ci } 1968141cc406Sopenharmony_ci 1969141cc406Sopenharmony_ci acceptable = true; 1970141cc406Sopenharmony_ci 1971141cc406Sopenharmony_ci for (j = 0; j < channels; j++) 1972141cc406Sopenharmony_ci { 1973141cc406Sopenharmony_ci avg[j] = 0; 1974141cc406Sopenharmony_ci for (i = 0; i < pixels; i++) { 1975141cc406Sopenharmony_ci if (dev->model->is_cis) { 1976141cc406Sopenharmony_ci val = line[i * 2 + j * 2 * pixels + 1] * 256 + line[i * 2 + j * 2 * pixels]; 1977141cc406Sopenharmony_ci } else { 1978141cc406Sopenharmony_ci val = line[i * 2 * channels + 2 * j + 1] * 256 + line[i * 2 * channels + 2 * j]; 1979141cc406Sopenharmony_ci } 1980141cc406Sopenharmony_ci avg[j] += val; 1981141cc406Sopenharmony_ci } 1982141cc406Sopenharmony_ci 1983141cc406Sopenharmony_ci avg[j] /= pixels; 1984141cc406Sopenharmony_ci } 1985141cc406Sopenharmony_ci 1986141cc406Sopenharmony_ci DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); 1987141cc406Sopenharmony_ci 1988141cc406Sopenharmony_ci acceptable = true; 1989141cc406Sopenharmony_ci 1990141cc406Sopenharmony_ci if (!acceptable) 1991141cc406Sopenharmony_ci { 1992141cc406Sopenharmony_ci avga = (avg[0] + avg[1] + avg[2]) / 3; 1993141cc406Sopenharmony_ci expr = (expr * avga) / avg[0]; 1994141cc406Sopenharmony_ci expg = (expg * avga) / avg[1]; 1995141cc406Sopenharmony_ci expb = (expb * avga) / avg[2]; 1996141cc406Sopenharmony_ci 1997141cc406Sopenharmony_ci /* keep exposure time in a working window */ 1998141cc406Sopenharmony_ci avge = (expr + expg + expb) / 3; 1999141cc406Sopenharmony_ci if (avge > 0x2000) 2000141cc406Sopenharmony_ci { 2001141cc406Sopenharmony_ci expr = (expr * 0x2000) / avge; 2002141cc406Sopenharmony_ci expg = (expg * 0x2000) / avge; 2003141cc406Sopenharmony_ci expb = (expb * 0x2000) / avge; 2004141cc406Sopenharmony_ci } 2005141cc406Sopenharmony_ci if (avge < 0x400) 2006141cc406Sopenharmony_ci { 2007141cc406Sopenharmony_ci expr = (expr * 0x400) / avge; 2008141cc406Sopenharmony_ci expg = (expg * 0x400) / avge; 2009141cc406Sopenharmony_ci expb = (expb * 0x400) / avge; 2010141cc406Sopenharmony_ci } 2011141cc406Sopenharmony_ci } 2012141cc406Sopenharmony_ci 2013141cc406Sopenharmony_ci turn++; 2014141cc406Sopenharmony_ci 2015141cc406Sopenharmony_ci } 2016141cc406Sopenharmony_ci while (!acceptable && turn < 100); 2017141cc406Sopenharmony_ci 2018141cc406Sopenharmony_ci DBG(DBG_info,"%s: acceptable exposure: 0x%04x,0x%04x,0x%04x\n", __func__, expr, expg, expb); 2019141cc406Sopenharmony_ci // BUG: we don't store the result of the last iteration to the sensor 2020141cc406Sopenharmony_ci return calib_sensor.exposure; 2021141cc406Sopenharmony_ci} 2022141cc406Sopenharmony_ci 2023141cc406Sopenharmony_ci/** 2024141cc406Sopenharmony_ci * average dark pixels of a scan 2025141cc406Sopenharmony_ci */ 2026141cc406Sopenharmony_cistatic int dark_average(std::uint8_t * data, unsigned int pixels, unsigned int lines, 2027141cc406Sopenharmony_ci unsigned int channels, unsigned int black) 2028141cc406Sopenharmony_ci{ 2029141cc406Sopenharmony_ci unsigned int i, j, k, average, count; 2030141cc406Sopenharmony_ci unsigned int avg[3]; 2031141cc406Sopenharmony_ci std::uint8_t val; 2032141cc406Sopenharmony_ci 2033141cc406Sopenharmony_ci /* computes average value on black margin */ 2034141cc406Sopenharmony_ci for (k = 0; k < channels; k++) 2035141cc406Sopenharmony_ci { 2036141cc406Sopenharmony_ci avg[k] = 0; 2037141cc406Sopenharmony_ci count = 0; 2038141cc406Sopenharmony_ci for (i = 0; i < lines; i++) 2039141cc406Sopenharmony_ci { 2040141cc406Sopenharmony_ci for (j = 0; j < black; j++) 2041141cc406Sopenharmony_ci { 2042141cc406Sopenharmony_ci val = data[i * channels * pixels + j + k]; 2043141cc406Sopenharmony_ci avg[k] += val; 2044141cc406Sopenharmony_ci count++; 2045141cc406Sopenharmony_ci } 2046141cc406Sopenharmony_ci } 2047141cc406Sopenharmony_ci if (count) 2048141cc406Sopenharmony_ci avg[k] /= count; 2049141cc406Sopenharmony_ci DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); 2050141cc406Sopenharmony_ci } 2051141cc406Sopenharmony_ci average = 0; 2052141cc406Sopenharmony_ci for (i = 0; i < channels; i++) 2053141cc406Sopenharmony_ci average += avg[i]; 2054141cc406Sopenharmony_ci average /= channels; 2055141cc406Sopenharmony_ci DBG(DBG_info, "%s: average = %d\n", __func__, average); 2056141cc406Sopenharmony_ci return average; 2057141cc406Sopenharmony_ci} 2058141cc406Sopenharmony_ci 2059141cc406Sopenharmony_ci 2060141cc406Sopenharmony_ci/** @brief calibration for AD frontend devices 2061141cc406Sopenharmony_ci * we do simple scan until all black_pixels are higher than 0, 2062141cc406Sopenharmony_ci * raising offset at each turn. 2063141cc406Sopenharmony_ci */ 2064141cc406Sopenharmony_cistatic void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor) 2065141cc406Sopenharmony_ci{ 2066141cc406Sopenharmony_ci DBG_HELPER(dbg); 2067141cc406Sopenharmony_ci (void) sensor; 2068141cc406Sopenharmony_ci 2069141cc406Sopenharmony_ci unsigned int channels; 2070141cc406Sopenharmony_ci int pass = 0; 2071141cc406Sopenharmony_ci unsigned adr, min; 2072141cc406Sopenharmony_ci unsigned int bottom, black_pixels; 2073141cc406Sopenharmony_ci 2074141cc406Sopenharmony_ci channels = 3; 2075141cc406Sopenharmony_ci 2076141cc406Sopenharmony_ci // FIXME: maybe reuse `sensor` 2077141cc406Sopenharmony_ci const auto& calib_sensor = sanei_genesys_find_sensor(dev, sensor.full_resolution, 3, 2078141cc406Sopenharmony_ci ScanMethod::FLATBED); 2079141cc406Sopenharmony_ci black_pixels = (calib_sensor.black_pixels * sensor.full_resolution) / calib_sensor.full_resolution; 2080141cc406Sopenharmony_ci 2081141cc406Sopenharmony_ci unsigned pixels = dev->model->x_size_calib_mm * sensor.full_resolution / MM_PER_INCH; 2082141cc406Sopenharmony_ci unsigned lines = CALIBRATION_LINES; 2083141cc406Sopenharmony_ci 2084141cc406Sopenharmony_ci if (dev->model->is_cis) { 2085141cc406Sopenharmony_ci lines = ((lines + 2) / 3) * 3; 2086141cc406Sopenharmony_ci } 2087141cc406Sopenharmony_ci 2088141cc406Sopenharmony_ci ScanSession session; 2089141cc406Sopenharmony_ci session.params.xres = sensor.full_resolution; 2090141cc406Sopenharmony_ci session.params.yres = sensor.full_resolution; 2091141cc406Sopenharmony_ci session.params.startx = 0; 2092141cc406Sopenharmony_ci session.params.starty = 0; 2093141cc406Sopenharmony_ci session.params.pixels = pixels; 2094141cc406Sopenharmony_ci session.params.lines = lines; 2095141cc406Sopenharmony_ci session.params.depth = 8; 2096141cc406Sopenharmony_ci session.params.channels = 3; 2097141cc406Sopenharmony_ci session.params.scan_method = dev->settings.scan_method; 2098141cc406Sopenharmony_ci session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; 2099141cc406Sopenharmony_ci session.params.color_filter = ColorFilter::RED; 2100141cc406Sopenharmony_ci session.params.contrast_adjustment = dev->settings.contrast; 2101141cc406Sopenharmony_ci session.params.brightness_adjustment = dev->settings.brightness; 2102141cc406Sopenharmony_ci session.params.flags = ScanFlag::DISABLE_SHADING; 2103141cc406Sopenharmony_ci if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { 2104141cc406Sopenharmony_ci session.params.flags |= ScanFlag::USE_XPA; 2105141cc406Sopenharmony_ci } 2106141cc406Sopenharmony_ci compute_session(dev, session, calib_sensor); 2107141cc406Sopenharmony_ci 2108141cc406Sopenharmony_ci /* scan first line of data with no gain */ 2109141cc406Sopenharmony_ci dev->frontend.set_gain(0, 0); 2110141cc406Sopenharmony_ci dev->frontend.set_gain(1, 0); 2111141cc406Sopenharmony_ci dev->frontend.set_gain(2, 0); 2112141cc406Sopenharmony_ci 2113141cc406Sopenharmony_ci std::vector<std::uint8_t> line; 2114141cc406Sopenharmony_ci 2115141cc406Sopenharmony_ci /* scan with no move */ 2116141cc406Sopenharmony_ci bottom = 1; 2117141cc406Sopenharmony_ci do 2118141cc406Sopenharmony_ci { 2119141cc406Sopenharmony_ci pass++; 2120141cc406Sopenharmony_ci dev->frontend.set_offset(0, bottom); 2121141cc406Sopenharmony_ci dev->frontend.set_offset(1, bottom); 2122141cc406Sopenharmony_ci dev->frontend.set_offset(2, bottom); 2123141cc406Sopenharmony_ci 2124141cc406Sopenharmony_ci dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session); 2125141cc406Sopenharmony_ci simple_scan(dev, calib_sensor, session, false, line, "ad_fe_offset_calibration"); 2126141cc406Sopenharmony_ci 2127141cc406Sopenharmony_ci if (is_testing_mode()) { 2128141cc406Sopenharmony_ci return; 2129141cc406Sopenharmony_ci } 2130141cc406Sopenharmony_ci 2131141cc406Sopenharmony_ci if (dbg_log_image_data()) { 2132141cc406Sopenharmony_ci char title[30]; 2133141cc406Sopenharmony_ci std::snprintf(title, 30, "gl646_offset%03d.tiff", static_cast<int>(bottom)); 2134141cc406Sopenharmony_ci write_tiff_file(title, line.data(), 8, channels, pixels, lines); 2135141cc406Sopenharmony_ci } 2136141cc406Sopenharmony_ci 2137141cc406Sopenharmony_ci min = 0; 2138141cc406Sopenharmony_ci for (unsigned y = 0; y < lines; y++) { 2139141cc406Sopenharmony_ci for (unsigned x = 0; x < black_pixels; x++) { 2140141cc406Sopenharmony_ci adr = (x + y * pixels) * channels; 2141141cc406Sopenharmony_ci if (line[adr] > min) 2142141cc406Sopenharmony_ci min = line[adr]; 2143141cc406Sopenharmony_ci if (line[adr + 1] > min) 2144141cc406Sopenharmony_ci min = line[adr + 1]; 2145141cc406Sopenharmony_ci if (line[adr + 2] > min) 2146141cc406Sopenharmony_ci min = line[adr + 2]; 2147141cc406Sopenharmony_ci } 2148141cc406Sopenharmony_ci } 2149141cc406Sopenharmony_ci 2150141cc406Sopenharmony_ci DBG(DBG_info, "%s: pass=%d, min=%d\n", __func__, pass, min); 2151141cc406Sopenharmony_ci bottom++; 2152141cc406Sopenharmony_ci } 2153141cc406Sopenharmony_ci while (pass < 128 && min == 0); 2154141cc406Sopenharmony_ci if (pass == 128) 2155141cc406Sopenharmony_ci { 2156141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_INVAL, "failed to find correct offset"); 2157141cc406Sopenharmony_ci } 2158141cc406Sopenharmony_ci 2159141cc406Sopenharmony_ci DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, 2160141cc406Sopenharmony_ci dev->frontend.get_offset(0), 2161141cc406Sopenharmony_ci dev->frontend.get_offset(1), 2162141cc406Sopenharmony_ci dev->frontend.get_offset(2)); 2163141cc406Sopenharmony_ci} 2164141cc406Sopenharmony_ci 2165141cc406Sopenharmony_ci/** 2166141cc406Sopenharmony_ci * This function does the offset calibration by scanning one line of the calibration 2167141cc406Sopenharmony_ci * area below scanner's top. There is a black margin and the remaining is white. 2168141cc406Sopenharmony_ci * genesys_search_start() must have been called so that the offsets and margins 2169141cc406Sopenharmony_ci * are already known. 2170141cc406Sopenharmony_ci * @param dev scanner's device 2171141cc406Sopenharmony_ci*/ 2172141cc406Sopenharmony_civoid CommandSetGl646::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, 2173141cc406Sopenharmony_ci Genesys_Register_Set& regs) const 2174141cc406Sopenharmony_ci{ 2175141cc406Sopenharmony_ci DBG_HELPER(dbg); 2176141cc406Sopenharmony_ci (void) regs; 2177141cc406Sopenharmony_ci 2178141cc406Sopenharmony_ci int pass = 0, avg; 2179141cc406Sopenharmony_ci int topavg, bottomavg; 2180141cc406Sopenharmony_ci int top, bottom, black_pixels; 2181141cc406Sopenharmony_ci 2182141cc406Sopenharmony_ci if (dev->model->adc_id == AdcId::AD_XP200) { 2183141cc406Sopenharmony_ci ad_fe_offset_calibration(dev, sensor); 2184141cc406Sopenharmony_ci return; 2185141cc406Sopenharmony_ci } 2186141cc406Sopenharmony_ci 2187141cc406Sopenharmony_ci /* setup for a RGB scan, one full sensor's width line */ 2188141cc406Sopenharmony_ci /* resolution is the one from the final scan */ 2189141cc406Sopenharmony_ci unsigned resolution = dev->settings.xres; 2190141cc406Sopenharmony_ci unsigned channels = 3; 2191141cc406Sopenharmony_ci 2192141cc406Sopenharmony_ci const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, 2193141cc406Sopenharmony_ci ScanMethod::FLATBED); 2194141cc406Sopenharmony_ci black_pixels = (calib_sensor.black_pixels * resolution) / calib_sensor.full_resolution; 2195141cc406Sopenharmony_ci 2196141cc406Sopenharmony_ci unsigned pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH; 2197141cc406Sopenharmony_ci unsigned lines = CALIBRATION_LINES; 2198141cc406Sopenharmony_ci if (dev->model->is_cis) { 2199141cc406Sopenharmony_ci lines = ((lines + 2) / 3) * 3; 2200141cc406Sopenharmony_ci } 2201141cc406Sopenharmony_ci 2202141cc406Sopenharmony_ci ScanSession session; 2203141cc406Sopenharmony_ci session.params.xres = resolution; 2204141cc406Sopenharmony_ci session.params.yres = resolution; 2205141cc406Sopenharmony_ci session.params.startx = 0; 2206141cc406Sopenharmony_ci session.params.starty = 0; 2207141cc406Sopenharmony_ci session.params.pixels = pixels; 2208141cc406Sopenharmony_ci session.params.lines = lines; 2209141cc406Sopenharmony_ci session.params.depth = 8; 2210141cc406Sopenharmony_ci session.params.channels = channels; 2211141cc406Sopenharmony_ci session.params.scan_method = dev->settings.scan_method; 2212141cc406Sopenharmony_ci session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; 2213141cc406Sopenharmony_ci session.params.color_filter = ColorFilter::RED; 2214141cc406Sopenharmony_ci session.params.contrast_adjustment = dev->settings.contrast; 2215141cc406Sopenharmony_ci session.params.brightness_adjustment = dev->settings.brightness; 2216141cc406Sopenharmony_ci session.params.flags = ScanFlag::DISABLE_SHADING; 2217141cc406Sopenharmony_ci if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { 2218141cc406Sopenharmony_ci session.params.flags |= ScanFlag::USE_XPA; 2219141cc406Sopenharmony_ci } 2220141cc406Sopenharmony_ci compute_session(dev, session, sensor); 2221141cc406Sopenharmony_ci 2222141cc406Sopenharmony_ci /* scan first line of data with no gain, but with offset from 2223141cc406Sopenharmony_ci * last calibration */ 2224141cc406Sopenharmony_ci dev->frontend.set_gain(0, 0); 2225141cc406Sopenharmony_ci dev->frontend.set_gain(1, 0); 2226141cc406Sopenharmony_ci dev->frontend.set_gain(2, 0); 2227141cc406Sopenharmony_ci 2228141cc406Sopenharmony_ci /* scan with no move */ 2229141cc406Sopenharmony_ci bottom = 90; 2230141cc406Sopenharmony_ci dev->frontend.set_offset(0, bottom); 2231141cc406Sopenharmony_ci dev->frontend.set_offset(1, bottom); 2232141cc406Sopenharmony_ci dev->frontend.set_offset(2, bottom); 2233141cc406Sopenharmony_ci 2234141cc406Sopenharmony_ci std::vector<std::uint8_t> first_line, second_line; 2235141cc406Sopenharmony_ci 2236141cc406Sopenharmony_ci dev->cmd_set->init_regs_for_scan_session(dev, sensor, &dev->reg, session); 2237141cc406Sopenharmony_ci simple_scan(dev, calib_sensor, session, false, first_line, "offset_first_line"); 2238141cc406Sopenharmony_ci 2239141cc406Sopenharmony_ci if (dbg_log_image_data()) { 2240141cc406Sopenharmony_ci char title[30]; 2241141cc406Sopenharmony_ci std::snprintf(title, 30, "gl646_offset%03d.tiff", bottom); 2242141cc406Sopenharmony_ci write_tiff_file(title, first_line.data(), 8, channels, pixels, lines); 2243141cc406Sopenharmony_ci } 2244141cc406Sopenharmony_ci bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels); 2245141cc406Sopenharmony_ci DBG(DBG_info, "%s: bottom avg=%d\n", __func__, bottomavg); 2246141cc406Sopenharmony_ci 2247141cc406Sopenharmony_ci /* now top value */ 2248141cc406Sopenharmony_ci top = 231; 2249141cc406Sopenharmony_ci dev->frontend.set_offset(0, top); 2250141cc406Sopenharmony_ci dev->frontend.set_offset(1, top); 2251141cc406Sopenharmony_ci dev->frontend.set_offset(2, top); 2252141cc406Sopenharmony_ci dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session); 2253141cc406Sopenharmony_ci simple_scan(dev, calib_sensor, session, false, second_line, "offset_second_line"); 2254141cc406Sopenharmony_ci 2255141cc406Sopenharmony_ci if (dbg_log_image_data()) { 2256141cc406Sopenharmony_ci char title[30]; 2257141cc406Sopenharmony_ci std::snprintf(title, 30, "gl646_offset%03d.tiff", top); 2258141cc406Sopenharmony_ci write_tiff_file(title, second_line.data(), 8, channels, pixels, lines); 2259141cc406Sopenharmony_ci } 2260141cc406Sopenharmony_ci topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); 2261141cc406Sopenharmony_ci DBG(DBG_info, "%s: top avg=%d\n", __func__, topavg); 2262141cc406Sopenharmony_ci 2263141cc406Sopenharmony_ci if (is_testing_mode()) { 2264141cc406Sopenharmony_ci return; 2265141cc406Sopenharmony_ci } 2266141cc406Sopenharmony_ci 2267141cc406Sopenharmony_ci /* loop until acceptable level */ 2268141cc406Sopenharmony_ci while ((pass < 32) && (top - bottom > 1)) 2269141cc406Sopenharmony_ci { 2270141cc406Sopenharmony_ci pass++; 2271141cc406Sopenharmony_ci 2272141cc406Sopenharmony_ci /* settings for new scan */ 2273141cc406Sopenharmony_ci dev->frontend.set_offset(0, (top + bottom) / 2); 2274141cc406Sopenharmony_ci dev->frontend.set_offset(1, (top + bottom) / 2); 2275141cc406Sopenharmony_ci dev->frontend.set_offset(2, (top + bottom) / 2); 2276141cc406Sopenharmony_ci 2277141cc406Sopenharmony_ci // scan with no move 2278141cc406Sopenharmony_ci dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session); 2279141cc406Sopenharmony_ci simple_scan(dev, calib_sensor, session, false, second_line, 2280141cc406Sopenharmony_ci "offset_calibration_i"); 2281141cc406Sopenharmony_ci 2282141cc406Sopenharmony_ci if (dbg_log_image_data()) { 2283141cc406Sopenharmony_ci char title[30]; 2284141cc406Sopenharmony_ci std::snprintf(title, 30, "gl646_offset%03d.tiff", dev->frontend.get_offset(1)); 2285141cc406Sopenharmony_ci write_tiff_file(title, second_line.data(), 8, channels, pixels, lines); 2286141cc406Sopenharmony_ci } 2287141cc406Sopenharmony_ci 2288141cc406Sopenharmony_ci avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); 2289141cc406Sopenharmony_ci DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); 2290141cc406Sopenharmony_ci 2291141cc406Sopenharmony_ci /* compute new boundaries */ 2292141cc406Sopenharmony_ci if (topavg == avg) 2293141cc406Sopenharmony_ci { 2294141cc406Sopenharmony_ci topavg = avg; 2295141cc406Sopenharmony_ci top = dev->frontend.get_offset(1); 2296141cc406Sopenharmony_ci } 2297141cc406Sopenharmony_ci else 2298141cc406Sopenharmony_ci { 2299141cc406Sopenharmony_ci bottomavg = avg; 2300141cc406Sopenharmony_ci bottom = dev->frontend.get_offset(1); 2301141cc406Sopenharmony_ci } 2302141cc406Sopenharmony_ci } 2303141cc406Sopenharmony_ci 2304141cc406Sopenharmony_ci DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, 2305141cc406Sopenharmony_ci dev->frontend.get_offset(0), 2306141cc406Sopenharmony_ci dev->frontend.get_offset(1), 2307141cc406Sopenharmony_ci dev->frontend.get_offset(2)); 2308141cc406Sopenharmony_ci} 2309141cc406Sopenharmony_ci 2310141cc406Sopenharmony_ci/** 2311141cc406Sopenharmony_ci * Alternative coarse gain calibration 2312141cc406Sopenharmony_ci * this on uses the settings from offset_calibration. First scan moves so 2313141cc406Sopenharmony_ci * we can go to calibration area for XPA. 2314141cc406Sopenharmony_ci * @param dev device for scan 2315141cc406Sopenharmony_ci * @param dpi resolutnio to calibrate at 2316141cc406Sopenharmony_ci */ 2317141cc406Sopenharmony_civoid CommandSetGl646::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, 2318141cc406Sopenharmony_ci Genesys_Register_Set& regs, int dpi) const 2319141cc406Sopenharmony_ci{ 2320141cc406Sopenharmony_ci DBG_HELPER(dbg); 2321141cc406Sopenharmony_ci (void) dpi; 2322141cc406Sopenharmony_ci (void) sensor; 2323141cc406Sopenharmony_ci (void) regs; 2324141cc406Sopenharmony_ci 2325141cc406Sopenharmony_ci float average[3]; 2326141cc406Sopenharmony_ci char title[32]; 2327141cc406Sopenharmony_ci 2328141cc406Sopenharmony_ci /* setup for a RGB scan, one full sensor's width line */ 2329141cc406Sopenharmony_ci /* resolution is the one from the final scan */ 2330141cc406Sopenharmony_ci unsigned channels = 3; 2331141cc406Sopenharmony_ci 2332141cc406Sopenharmony_ci // BUG: the following comment is incorrect 2333141cc406Sopenharmony_ci // we are searching a sensor resolution */ 2334141cc406Sopenharmony_ci const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->settings.xres, channels, 2335141cc406Sopenharmony_ci ScanMethod::FLATBED); 2336141cc406Sopenharmony_ci 2337141cc406Sopenharmony_ci unsigned pixels = 0; 2338141cc406Sopenharmony_ci float start = 0; 2339141cc406Sopenharmony_ci if (dev->settings.scan_method == ScanMethod::FLATBED) { 2340141cc406Sopenharmony_ci pixels = dev->model->x_size_calib_mm * dev->settings.xres / MM_PER_INCH; 2341141cc406Sopenharmony_ci } else { 2342141cc406Sopenharmony_ci start = dev->model->x_offset_ta; 2343141cc406Sopenharmony_ci pixels = static_cast<unsigned>( 2344141cc406Sopenharmony_ci (dev->model->x_size_ta * dev->settings.xres) / MM_PER_INCH); 2345141cc406Sopenharmony_ci } 2346141cc406Sopenharmony_ci 2347141cc406Sopenharmony_ci unsigned lines = CALIBRATION_LINES; 2348141cc406Sopenharmony_ci // round up to multiple of 3 in case of CIS scanner 2349141cc406Sopenharmony_ci if (dev->model->is_cis) { 2350141cc406Sopenharmony_ci lines = ((lines + 2) / 3) * 3; 2351141cc406Sopenharmony_ci } 2352141cc406Sopenharmony_ci 2353141cc406Sopenharmony_ci start = static_cast<float>((start * dev->settings.xres) / MM_PER_INCH); 2354141cc406Sopenharmony_ci 2355141cc406Sopenharmony_ci ScanSession session; 2356141cc406Sopenharmony_ci session.params.xres = dev->settings.xres; 2357141cc406Sopenharmony_ci session.params.yres = dev->settings.xres; 2358141cc406Sopenharmony_ci session.params.startx = static_cast<unsigned>(start); 2359141cc406Sopenharmony_ci session.params.starty = 0; 2360141cc406Sopenharmony_ci session.params.pixels = pixels; 2361141cc406Sopenharmony_ci session.params.lines = lines; 2362141cc406Sopenharmony_ci session.params.depth = 8; 2363141cc406Sopenharmony_ci session.params.channels = channels; 2364141cc406Sopenharmony_ci session.params.scan_method = dev->settings.scan_method; 2365141cc406Sopenharmony_ci session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; 2366141cc406Sopenharmony_ci session.params.color_filter = ColorFilter::RED; 2367141cc406Sopenharmony_ci session.params.contrast_adjustment = dev->settings.contrast; 2368141cc406Sopenharmony_ci session.params.brightness_adjustment = dev->settings.brightness; 2369141cc406Sopenharmony_ci session.params.flags = ScanFlag::DISABLE_SHADING; 2370141cc406Sopenharmony_ci if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { 2371141cc406Sopenharmony_ci session.params.flags |= ScanFlag::USE_XPA; 2372141cc406Sopenharmony_ci } 2373141cc406Sopenharmony_ci compute_session(dev, session, calib_sensor); 2374141cc406Sopenharmony_ci 2375141cc406Sopenharmony_ci /* start gain value */ 2376141cc406Sopenharmony_ci dev->frontend.set_gain(0, 1); 2377141cc406Sopenharmony_ci dev->frontend.set_gain(1, 1); 2378141cc406Sopenharmony_ci dev->frontend.set_gain(2, 1); 2379141cc406Sopenharmony_ci 2380141cc406Sopenharmony_ci average[0] = 0; 2381141cc406Sopenharmony_ci average[1] = 0; 2382141cc406Sopenharmony_ci average[2] = 0; 2383141cc406Sopenharmony_ci 2384141cc406Sopenharmony_ci unsigned pass = 0; 2385141cc406Sopenharmony_ci 2386141cc406Sopenharmony_ci std::vector<std::uint8_t> line; 2387141cc406Sopenharmony_ci 2388141cc406Sopenharmony_ci /* loop until each channel raises to acceptable level */ 2389141cc406Sopenharmony_ci while (((average[0] < calib_sensor.gain_white_ref) || 2390141cc406Sopenharmony_ci (average[1] < calib_sensor.gain_white_ref) || 2391141cc406Sopenharmony_ci (average[2] < calib_sensor.gain_white_ref)) && (pass < 30)) 2392141cc406Sopenharmony_ci { 2393141cc406Sopenharmony_ci // scan with no move 2394141cc406Sopenharmony_ci dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, &dev->reg, session); 2395141cc406Sopenharmony_ci simple_scan(dev, calib_sensor, session, false, line, "coarse_gain_calibration"); 2396141cc406Sopenharmony_ci 2397141cc406Sopenharmony_ci if (dbg_log_image_data()) { 2398141cc406Sopenharmony_ci std::sprintf(title, "gl646_gain%02d.tiff", pass); 2399141cc406Sopenharmony_ci write_tiff_file(title, line.data(), 8, channels, pixels, lines); 2400141cc406Sopenharmony_ci } 2401141cc406Sopenharmony_ci pass++; 2402141cc406Sopenharmony_ci 2403141cc406Sopenharmony_ci // average high level for each channel and compute gain to reach the target code 2404141cc406Sopenharmony_ci // we only use the central half of the CCD data 2405141cc406Sopenharmony_ci for (unsigned k = 0; k < channels; k++) { 2406141cc406Sopenharmony_ci 2407141cc406Sopenharmony_ci // we find the maximum white value, so we can deduce a threshold 2408141cc406Sopenharmony_ci // to average white values 2409141cc406Sopenharmony_ci unsigned maximum = 0; 2410141cc406Sopenharmony_ci for (unsigned i = 0; i < lines; i++) { 2411141cc406Sopenharmony_ci for (unsigned j = 0; j < pixels; j++) { 2412141cc406Sopenharmony_ci unsigned val = line[i * channels * pixels + j + k]; 2413141cc406Sopenharmony_ci maximum = std::max(maximum, val); 2414141cc406Sopenharmony_ci } 2415141cc406Sopenharmony_ci } 2416141cc406Sopenharmony_ci 2417141cc406Sopenharmony_ci maximum = static_cast<int>(maximum * 0.9); 2418141cc406Sopenharmony_ci 2419141cc406Sopenharmony_ci // computes white average 2420141cc406Sopenharmony_ci average[k] = 0; 2421141cc406Sopenharmony_ci unsigned count = 0; 2422141cc406Sopenharmony_ci for (unsigned i = 0; i < lines; i++) { 2423141cc406Sopenharmony_ci for (unsigned j = 0; j < pixels; j++) { 2424141cc406Sopenharmony_ci // averaging only white points allow us not to care about dark margins 2425141cc406Sopenharmony_ci unsigned val = line[i * channels * pixels + j + k]; 2426141cc406Sopenharmony_ci if (val > maximum) { 2427141cc406Sopenharmony_ci average[k] += val; 2428141cc406Sopenharmony_ci count++; 2429141cc406Sopenharmony_ci } 2430141cc406Sopenharmony_ci } 2431141cc406Sopenharmony_ci } 2432141cc406Sopenharmony_ci average[k] = average[k] / count; 2433141cc406Sopenharmony_ci 2434141cc406Sopenharmony_ci // adjusts gain for the channel 2435141cc406Sopenharmony_ci if (average[k] < calib_sensor.gain_white_ref) { 2436141cc406Sopenharmony_ci dev->frontend.set_gain(k, dev->frontend.get_gain(k) + 1); 2437141cc406Sopenharmony_ci } 2438141cc406Sopenharmony_ci 2439141cc406Sopenharmony_ci DBG(DBG_info, "%s: channel %d, average = %.2f, gain = %d\n", __func__, k, average[k], 2440141cc406Sopenharmony_ci dev->frontend.get_gain(k)); 2441141cc406Sopenharmony_ci } 2442141cc406Sopenharmony_ci } 2443141cc406Sopenharmony_ci 2444141cc406Sopenharmony_ci DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__, 2445141cc406Sopenharmony_ci dev->frontend.get_gain(0), 2446141cc406Sopenharmony_ci dev->frontend.get_gain(1), 2447141cc406Sopenharmony_ci dev->frontend.get_gain(2)); 2448141cc406Sopenharmony_ci} 2449141cc406Sopenharmony_ci 2450141cc406Sopenharmony_ci/** 2451141cc406Sopenharmony_ci * sets up the scanner's register for warming up. We scan 2 lines without moving. 2452141cc406Sopenharmony_ci * 2453141cc406Sopenharmony_ci */ 2454141cc406Sopenharmony_civoid CommandSetGl646::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, 2455141cc406Sopenharmony_ci Genesys_Register_Set* local_reg) const 2456141cc406Sopenharmony_ci{ 2457141cc406Sopenharmony_ci DBG_HELPER(dbg); 2458141cc406Sopenharmony_ci (void) sensor; 2459141cc406Sopenharmony_ci 2460141cc406Sopenharmony_ci dev->frontend = dev->frontend_initial; 2461141cc406Sopenharmony_ci 2462141cc406Sopenharmony_ci unsigned resolution = 300; 2463141cc406Sopenharmony_ci const auto& local_sensor = sanei_genesys_find_sensor(dev, resolution, 1, 2464141cc406Sopenharmony_ci dev->settings.scan_method); 2465141cc406Sopenharmony_ci 2466141cc406Sopenharmony_ci // set up for a full width 2 lines gray scan without moving 2467141cc406Sopenharmony_ci unsigned pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH; 2468141cc406Sopenharmony_ci 2469141cc406Sopenharmony_ci ScanSession session; 2470141cc406Sopenharmony_ci session.params.xres = resolution; 2471141cc406Sopenharmony_ci session.params.yres = resolution; 2472141cc406Sopenharmony_ci session.params.startx = 0; 2473141cc406Sopenharmony_ci session.params.starty = 0; 2474141cc406Sopenharmony_ci session.params.pixels = pixels; 2475141cc406Sopenharmony_ci session.params.lines = 2; 2476141cc406Sopenharmony_ci session.params.depth = dev->model->bpp_gray_values.front(); 2477141cc406Sopenharmony_ci session.params.channels = 1; 2478141cc406Sopenharmony_ci session.params.scan_method = dev->settings.scan_method; 2479141cc406Sopenharmony_ci session.params.scan_mode = ScanColorMode::GRAY; 2480141cc406Sopenharmony_ci session.params.color_filter = ColorFilter::RED; 2481141cc406Sopenharmony_ci session.params.contrast_adjustment = 0; 2482141cc406Sopenharmony_ci session.params.brightness_adjustment = 0; 2483141cc406Sopenharmony_ci session.params.flags = ScanFlag::DISABLE_SHADING | 2484141cc406Sopenharmony_ci ScanFlag::DISABLE_GAMMA; 2485141cc406Sopenharmony_ci if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { 2486141cc406Sopenharmony_ci session.params.flags |= ScanFlag::USE_XPA; 2487141cc406Sopenharmony_ci } 2488141cc406Sopenharmony_ci compute_session(dev, session, local_sensor); 2489141cc406Sopenharmony_ci 2490141cc406Sopenharmony_ci dev->cmd_set->init_regs_for_scan_session(dev, local_sensor, &dev->reg, session); 2491141cc406Sopenharmony_ci 2492141cc406Sopenharmony_ci /* we are not going to move, so clear these bits */ 2493141cc406Sopenharmony_ci dev->reg.find_reg(0x02).value &= ~REG_0x02_FASTFED; 2494141cc406Sopenharmony_ci 2495141cc406Sopenharmony_ci /* copy to local_reg */ 2496141cc406Sopenharmony_ci *local_reg = dev->reg; 2497141cc406Sopenharmony_ci 2498141cc406Sopenharmony_ci /* turn off motor during this scan */ 2499141cc406Sopenharmony_ci sanei_genesys_set_motor_power(*local_reg, false); 2500141cc406Sopenharmony_ci 2501141cc406Sopenharmony_ci // now registers are ok, write them to scanner 2502141cc406Sopenharmony_ci gl646_set_fe(dev, local_sensor, AFE_SET, session.params.xres); 2503141cc406Sopenharmony_ci} 2504141cc406Sopenharmony_ci 2505141cc406Sopenharmony_ci/* * 2506141cc406Sopenharmony_ci * initialize ASIC : registers, motor tables, and gamma tables 2507141cc406Sopenharmony_ci * then ensure scanner's head is at home 2508141cc406Sopenharmony_ci * @param dev device description of the scanner to initialize 2509141cc406Sopenharmony_ci */ 2510141cc406Sopenharmony_civoid CommandSetGl646::init(Genesys_Device* dev) const 2511141cc406Sopenharmony_ci{ 2512141cc406Sopenharmony_ci DBG_INIT(); 2513141cc406Sopenharmony_ci DBG_HELPER(dbg); 2514141cc406Sopenharmony_ci 2515141cc406Sopenharmony_ci std::uint8_t val = 0; 2516141cc406Sopenharmony_ci std::uint32_t addr = 0xdead; 2517141cc406Sopenharmony_ci size_t len; 2518141cc406Sopenharmony_ci 2519141cc406Sopenharmony_ci // to detect real power up condition, we write to REG_0x41 with pwrbit set, then read it back. 2520141cc406Sopenharmony_ci // When scanner is cold (just replugged) PWRBIT will be set in the returned value 2521141cc406Sopenharmony_ci auto status = scanner_read_status(*dev); 2522141cc406Sopenharmony_ci if (status.is_replugged) { 2523141cc406Sopenharmony_ci DBG(DBG_info, "%s: device is cold\n", __func__); 2524141cc406Sopenharmony_ci } else { 2525141cc406Sopenharmony_ci DBG(DBG_info, "%s: device is hot\n", __func__); 2526141cc406Sopenharmony_ci } 2527141cc406Sopenharmony_ci 2528141cc406Sopenharmony_ci const auto& sensor = sanei_genesys_find_sensor_any(dev); 2529141cc406Sopenharmony_ci 2530141cc406Sopenharmony_ci /* if scanning session hasn't been initialized, set it up */ 2531141cc406Sopenharmony_ci if (!dev->already_initialized) 2532141cc406Sopenharmony_ci { 2533141cc406Sopenharmony_ci dev->dark_average_data.clear(); 2534141cc406Sopenharmony_ci dev->white_average_data.clear(); 2535141cc406Sopenharmony_ci 2536141cc406Sopenharmony_ci dev->settings.color_filter = ColorFilter::GREEN; 2537141cc406Sopenharmony_ci 2538141cc406Sopenharmony_ci /* Set default values for registers */ 2539141cc406Sopenharmony_ci gl646_init_regs (dev); 2540141cc406Sopenharmony_ci 2541141cc406Sopenharmony_ci // Init shading data 2542141cc406Sopenharmony_ci sanei_genesys_init_shading_data(dev, sensor, 2543141cc406Sopenharmony_ci dev->model->x_size_calib_mm * sensor.full_resolution / 2544141cc406Sopenharmony_ci MM_PER_INCH); 2545141cc406Sopenharmony_ci 2546141cc406Sopenharmony_ci dev->initial_regs = dev->reg; 2547141cc406Sopenharmony_ci } 2548141cc406Sopenharmony_ci 2549141cc406Sopenharmony_ci // execute physical unit init only if cold 2550141cc406Sopenharmony_ci if (status.is_replugged) 2551141cc406Sopenharmony_ci { 2552141cc406Sopenharmony_ci DBG(DBG_info, "%s: device is cold\n", __func__); 2553141cc406Sopenharmony_ci 2554141cc406Sopenharmony_ci val = 0x04; 2555141cc406Sopenharmony_ci dev->interface->get_usb_device().control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, 2556141cc406Sopenharmony_ci VALUE_INIT, INDEX, 1, &val); 2557141cc406Sopenharmony_ci 2558141cc406Sopenharmony_ci // ASIC reset 2559141cc406Sopenharmony_ci dev->interface->write_register(0x0e, 0x00); 2560141cc406Sopenharmony_ci dev->interface->sleep_ms(100); 2561141cc406Sopenharmony_ci 2562141cc406Sopenharmony_ci // Write initial registers 2563141cc406Sopenharmony_ci dev->interface->write_registers(dev->reg); 2564141cc406Sopenharmony_ci 2565141cc406Sopenharmony_ci // send gamma tables if needed 2566141cc406Sopenharmony_ci dev->cmd_set->send_gamma_table(dev, sensor); 2567141cc406Sopenharmony_ci 2568141cc406Sopenharmony_ci // Set powersaving(default = 15 minutes) 2569141cc406Sopenharmony_ci dev->cmd_set->set_powersaving(dev, 15); 2570141cc406Sopenharmony_ci } 2571141cc406Sopenharmony_ci 2572141cc406Sopenharmony_ci // Set analog frontend 2573141cc406Sopenharmony_ci gl646_set_fe(dev, sensor, AFE_INIT, 0); 2574141cc406Sopenharmony_ci 2575141cc406Sopenharmony_ci /* GPO enabling for XP200 */ 2576141cc406Sopenharmony_ci if (dev->model->sensor_id == SensorId::CIS_XP200) { 2577141cc406Sopenharmony_ci dev->interface->write_register(0x68, dev->gpo.regs.get_value(0x68)); 2578141cc406Sopenharmony_ci dev->interface->write_register(0x69, dev->gpo.regs.get_value(0x69)); 2579141cc406Sopenharmony_ci 2580141cc406Sopenharmony_ci // enable GPIO 2581141cc406Sopenharmony_ci gl646_gpio_output_enable(dev->interface->get_usb_device(), 6); 2582141cc406Sopenharmony_ci 2583141cc406Sopenharmony_ci // writes 0 to GPIO 2584141cc406Sopenharmony_ci gl646_gpio_write(dev->interface->get_usb_device(), 0); 2585141cc406Sopenharmony_ci 2586141cc406Sopenharmony_ci // clear GPIO enable 2587141cc406Sopenharmony_ci gl646_gpio_output_enable(dev->interface->get_usb_device(), 0); 2588141cc406Sopenharmony_ci 2589141cc406Sopenharmony_ci dev->interface->write_register(0x66, 0x10); 2590141cc406Sopenharmony_ci dev->interface->write_register(0x66, 0x00); 2591141cc406Sopenharmony_ci dev->interface->write_register(0x66, 0x10); 2592141cc406Sopenharmony_ci } 2593141cc406Sopenharmony_ci 2594141cc406Sopenharmony_ci /* MD6471/G2410 and XP200 read/write data from an undocumented memory area which 2595141cc406Sopenharmony_ci * is after the second slope table */ 2596141cc406Sopenharmony_ci if (dev->model->gpio_id != GpioId::HP3670 && 2597141cc406Sopenharmony_ci dev->model->gpio_id != GpioId::HP2400) 2598141cc406Sopenharmony_ci { 2599141cc406Sopenharmony_ci switch (sensor.full_resolution) 2600141cc406Sopenharmony_ci { 2601141cc406Sopenharmony_ci case 600: 2602141cc406Sopenharmony_ci addr = 0x08200; 2603141cc406Sopenharmony_ci break; 2604141cc406Sopenharmony_ci case 1200: 2605141cc406Sopenharmony_ci addr = 0x10200; 2606141cc406Sopenharmony_ci break; 2607141cc406Sopenharmony_ci case 2400: 2608141cc406Sopenharmony_ci addr = 0x1fa00; 2609141cc406Sopenharmony_ci break; 2610141cc406Sopenharmony_ci } 2611141cc406Sopenharmony_ci sanei_genesys_set_buffer_address(dev, addr); 2612141cc406Sopenharmony_ci 2613141cc406Sopenharmony_ci sanei_usb_set_timeout (2 * 1000); 2614141cc406Sopenharmony_ci len = 6; 2615141cc406Sopenharmony_ci // for some reason, read fails here for MD6471, HP2300 and XP200 one time out of 2616141cc406Sopenharmony_ci // 2 scanimage launches 2617141cc406Sopenharmony_ci try { 2618141cc406Sopenharmony_ci dev->interface->bulk_read_data(0x45, dev->control, len); 2619141cc406Sopenharmony_ci } catch (...) { 2620141cc406Sopenharmony_ci dev->interface->bulk_read_data(0x45, dev->control, len); 2621141cc406Sopenharmony_ci } 2622141cc406Sopenharmony_ci sanei_usb_set_timeout (30 * 1000); 2623141cc406Sopenharmony_ci } 2624141cc406Sopenharmony_ci else 2625141cc406Sopenharmony_ci /* HP2400 and HP3670 case */ 2626141cc406Sopenharmony_ci { 2627141cc406Sopenharmony_ci dev->control[0] = 0x00; 2628141cc406Sopenharmony_ci dev->control[1] = 0x00; 2629141cc406Sopenharmony_ci dev->control[2] = 0x01; 2630141cc406Sopenharmony_ci dev->control[3] = 0x00; 2631141cc406Sopenharmony_ci dev->control[4] = 0x00; 2632141cc406Sopenharmony_ci dev->control[5] = 0x00; 2633141cc406Sopenharmony_ci } 2634141cc406Sopenharmony_ci 2635141cc406Sopenharmony_ci /* ensure head is correctly parked, and check lock */ 2636141cc406Sopenharmony_ci if (!dev->model->is_sheetfed) { 2637141cc406Sopenharmony_ci move_back_home(dev, true); 2638141cc406Sopenharmony_ci } 2639141cc406Sopenharmony_ci 2640141cc406Sopenharmony_ci /* here session and device are initialized */ 2641141cc406Sopenharmony_ci dev->already_initialized = true; 2642141cc406Sopenharmony_ci} 2643141cc406Sopenharmony_ci 2644141cc406Sopenharmony_cistatic void simple_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, 2645141cc406Sopenharmony_ci const ScanSession& session, bool move, 2646141cc406Sopenharmony_ci std::vector<std::uint8_t>& data, const char* scan_identifier) 2647141cc406Sopenharmony_ci{ 2648141cc406Sopenharmony_ci unsigned lines = session.output_line_count; 2649141cc406Sopenharmony_ci if (!dev->model->is_cis) { 2650141cc406Sopenharmony_ci lines++; 2651141cc406Sopenharmony_ci } 2652141cc406Sopenharmony_ci 2653141cc406Sopenharmony_ci std::size_t size = lines * session.params.pixels; 2654141cc406Sopenharmony_ci unsigned bpp = session.params.depth == 16 ? 2 : 1; 2655141cc406Sopenharmony_ci 2656141cc406Sopenharmony_ci size *= bpp * session.params.channels; 2657141cc406Sopenharmony_ci data.clear(); 2658141cc406Sopenharmony_ci data.resize(size); 2659141cc406Sopenharmony_ci 2660141cc406Sopenharmony_ci // initialize frontend 2661141cc406Sopenharmony_ci gl646_set_fe(dev, sensor, AFE_SET, session.params.xres); 2662141cc406Sopenharmony_ci 2663141cc406Sopenharmony_ci // no watch dog for simple scan 2664141cc406Sopenharmony_ci dev->reg.find_reg(0x01).value &= ~REG_0x01_DOGENB; 2665141cc406Sopenharmony_ci 2666141cc406Sopenharmony_ci /* one table movement for simple scan */ 2667141cc406Sopenharmony_ci dev->reg.find_reg(0x02).value &= ~REG_0x02_FASTFED; 2668141cc406Sopenharmony_ci 2669141cc406Sopenharmony_ci if (!move) { 2670141cc406Sopenharmony_ci sanei_genesys_set_motor_power(dev->reg, false); 2671141cc406Sopenharmony_ci } 2672141cc406Sopenharmony_ci 2673141cc406Sopenharmony_ci /* no automatic go home when using XPA */ 2674141cc406Sopenharmony_ci if (session.params.scan_method == ScanMethod::TRANSPARENCY) { 2675141cc406Sopenharmony_ci dev->reg.find_reg(0x02).value &= ~REG_0x02_AGOHOME; 2676141cc406Sopenharmony_ci } 2677141cc406Sopenharmony_ci 2678141cc406Sopenharmony_ci // write scan registers 2679141cc406Sopenharmony_ci dev->interface->write_registers(dev->reg); 2680141cc406Sopenharmony_ci 2681141cc406Sopenharmony_ci // starts scan 2682141cc406Sopenharmony_ci dev->cmd_set->begin_scan(dev, sensor, &dev->reg, move); 2683141cc406Sopenharmony_ci 2684141cc406Sopenharmony_ci if (is_testing_mode()) { 2685141cc406Sopenharmony_ci dev->interface->test_checkpoint(scan_identifier); 2686141cc406Sopenharmony_ci return; 2687141cc406Sopenharmony_ci } 2688141cc406Sopenharmony_ci 2689141cc406Sopenharmony_ci wait_until_buffer_non_empty(dev, true); 2690141cc406Sopenharmony_ci 2691141cc406Sopenharmony_ci // now we're on target, we can read data 2692141cc406Sopenharmony_ci sanei_genesys_read_data_from_scanner(dev, data.data(), size); 2693141cc406Sopenharmony_ci 2694141cc406Sopenharmony_ci /* in case of CIS scanner, we must reorder data */ 2695141cc406Sopenharmony_ci if (dev->model->is_cis && session.params.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) { 2696141cc406Sopenharmony_ci auto pixels_count = session.params.pixels; 2697141cc406Sopenharmony_ci 2698141cc406Sopenharmony_ci std::vector<std::uint8_t> buffer(pixels_count * 3 * bpp); 2699141cc406Sopenharmony_ci 2700141cc406Sopenharmony_ci if (bpp == 1) { 2701141cc406Sopenharmony_ci for (unsigned y = 0; y < lines; y++) { 2702141cc406Sopenharmony_ci // reorder line 2703141cc406Sopenharmony_ci for (unsigned x = 0; x < pixels_count; x++) { 2704141cc406Sopenharmony_ci buffer[x * 3] = data[y * pixels_count * 3 + x]; 2705141cc406Sopenharmony_ci buffer[x * 3 + 1] = data[y * pixels_count * 3 + pixels_count + x]; 2706141cc406Sopenharmony_ci buffer[x * 3 + 2] = data[y * pixels_count * 3 + 2 * pixels_count + x]; 2707141cc406Sopenharmony_ci } 2708141cc406Sopenharmony_ci // copy line back 2709141cc406Sopenharmony_ci std::memcpy(data.data() + pixels_count * 3 * y, buffer.data(), pixels_count * 3); 2710141cc406Sopenharmony_ci } 2711141cc406Sopenharmony_ci } else { 2712141cc406Sopenharmony_ci for (unsigned y = 0; y < lines; y++) { 2713141cc406Sopenharmony_ci // reorder line 2714141cc406Sopenharmony_ci auto pixels_count = session.params.pixels; 2715141cc406Sopenharmony_ci for (unsigned x = 0; x < pixels_count; x++) { 2716141cc406Sopenharmony_ci buffer[x * 6] = data[y * pixels_count * 6 + x * 2]; 2717141cc406Sopenharmony_ci buffer[x * 6 + 1] = data[y * pixels_count * 6 + x * 2 + 1]; 2718141cc406Sopenharmony_ci buffer[x * 6 + 2] = data[y * pixels_count * 6 + 2 * pixels_count + x * 2]; 2719141cc406Sopenharmony_ci buffer[x * 6 + 3] = data[y * pixels_count * 6 + 2 * pixels_count + x * 2 + 1]; 2720141cc406Sopenharmony_ci buffer[x * 6 + 4] = data[y * pixels_count * 6 + 4 * pixels_count + x * 2]; 2721141cc406Sopenharmony_ci buffer[x * 6 + 5] = data[y * pixels_count * 6 + 4 * pixels_count + x * 2 + 1]; 2722141cc406Sopenharmony_ci } 2723141cc406Sopenharmony_ci // copy line back 2724141cc406Sopenharmony_ci std::memcpy(data.data() + pixels_count * 6 * y, buffer.data(),pixels_count * 6); 2725141cc406Sopenharmony_ci } 2726141cc406Sopenharmony_ci } 2727141cc406Sopenharmony_ci } 2728141cc406Sopenharmony_ci 2729141cc406Sopenharmony_ci // end scan , waiting the motor to stop if needed (if moving), but without ejecting doc 2730141cc406Sopenharmony_ci end_scan_impl(dev, &dev->reg, true, false); 2731141cc406Sopenharmony_ci} 2732141cc406Sopenharmony_ci 2733141cc406Sopenharmony_ci/** 2734141cc406Sopenharmony_ci * update the status of the required sensor in the scanner session 2735141cc406Sopenharmony_ci * the button fields are used to make events 'sticky' 2736141cc406Sopenharmony_ci */ 2737141cc406Sopenharmony_civoid CommandSetGl646::update_hardware_sensors(Genesys_Scanner* session) const 2738141cc406Sopenharmony_ci{ 2739141cc406Sopenharmony_ci DBG_HELPER(dbg); 2740141cc406Sopenharmony_ci Genesys_Device *dev = session->dev; 2741141cc406Sopenharmony_ci std::uint8_t value; 2742141cc406Sopenharmony_ci 2743141cc406Sopenharmony_ci // do what is needed to get a new set of events, but try to not loose any of them. 2744141cc406Sopenharmony_ci gl646_gpio_read(dev->interface->get_usb_device(), &value); 2745141cc406Sopenharmony_ci DBG(DBG_io, "%s: GPIO=0x%02x\n", __func__, value); 2746141cc406Sopenharmony_ci 2747141cc406Sopenharmony_ci // scan button 2748141cc406Sopenharmony_ci if (dev->model->buttons & GENESYS_HAS_SCAN_SW) { 2749141cc406Sopenharmony_ci switch (dev->model->gpio_id) { 2750141cc406Sopenharmony_ci case GpioId::XP200: 2751141cc406Sopenharmony_ci session->buttons[BUTTON_SCAN_SW].write((value & 0x02) != 0); 2752141cc406Sopenharmony_ci break; 2753141cc406Sopenharmony_ci case GpioId::MD_5345: 2754141cc406Sopenharmony_ci session->buttons[BUTTON_SCAN_SW].write(value == 0x16); 2755141cc406Sopenharmony_ci break; 2756141cc406Sopenharmony_ci case GpioId::HP2300: 2757141cc406Sopenharmony_ci session->buttons[BUTTON_SCAN_SW].write(value == 0x6c); 2758141cc406Sopenharmony_ci break; 2759141cc406Sopenharmony_ci case GpioId::HP3670: 2760141cc406Sopenharmony_ci case GpioId::HP2400: 2761141cc406Sopenharmony_ci session->buttons[BUTTON_SCAN_SW].write((value & 0x20) == 0); 2762141cc406Sopenharmony_ci break; 2763141cc406Sopenharmony_ci default: 2764141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); 2765141cc406Sopenharmony_ci } 2766141cc406Sopenharmony_ci } 2767141cc406Sopenharmony_ci 2768141cc406Sopenharmony_ci // email button 2769141cc406Sopenharmony_ci if (dev->model->buttons & GENESYS_HAS_EMAIL_SW) { 2770141cc406Sopenharmony_ci switch (dev->model->gpio_id) { 2771141cc406Sopenharmony_ci case GpioId::MD_5345: 2772141cc406Sopenharmony_ci session->buttons[BUTTON_EMAIL_SW].write(value == 0x12); 2773141cc406Sopenharmony_ci break; 2774141cc406Sopenharmony_ci case GpioId::HP3670: 2775141cc406Sopenharmony_ci case GpioId::HP2400: 2776141cc406Sopenharmony_ci session->buttons[BUTTON_EMAIL_SW].write((value & 0x08) == 0); 2777141cc406Sopenharmony_ci break; 2778141cc406Sopenharmony_ci default: 2779141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); 2780141cc406Sopenharmony_ci } 2781141cc406Sopenharmony_ci } 2782141cc406Sopenharmony_ci 2783141cc406Sopenharmony_ci // copy button 2784141cc406Sopenharmony_ci if (dev->model->buttons & GENESYS_HAS_COPY_SW) { 2785141cc406Sopenharmony_ci switch (dev->model->gpio_id) { 2786141cc406Sopenharmony_ci case GpioId::MD_5345: 2787141cc406Sopenharmony_ci session->buttons[BUTTON_COPY_SW].write(value == 0x11); 2788141cc406Sopenharmony_ci break; 2789141cc406Sopenharmony_ci case GpioId::HP2300: 2790141cc406Sopenharmony_ci session->buttons[BUTTON_COPY_SW].write(value == 0x5c); 2791141cc406Sopenharmony_ci break; 2792141cc406Sopenharmony_ci case GpioId::HP3670: 2793141cc406Sopenharmony_ci case GpioId::HP2400: 2794141cc406Sopenharmony_ci session->buttons[BUTTON_COPY_SW].write((value & 0x10) == 0); 2795141cc406Sopenharmony_ci break; 2796141cc406Sopenharmony_ci default: 2797141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); 2798141cc406Sopenharmony_ci } 2799141cc406Sopenharmony_ci } 2800141cc406Sopenharmony_ci 2801141cc406Sopenharmony_ci // power button 2802141cc406Sopenharmony_ci if (dev->model->buttons & GENESYS_HAS_POWER_SW) { 2803141cc406Sopenharmony_ci switch (dev->model->gpio_id) { 2804141cc406Sopenharmony_ci case GpioId::MD_5345: 2805141cc406Sopenharmony_ci session->buttons[BUTTON_POWER_SW].write(value == 0x14); 2806141cc406Sopenharmony_ci break; 2807141cc406Sopenharmony_ci default: 2808141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); 2809141cc406Sopenharmony_ci } 2810141cc406Sopenharmony_ci } 2811141cc406Sopenharmony_ci 2812141cc406Sopenharmony_ci // ocr button 2813141cc406Sopenharmony_ci if (dev->model->buttons & GENESYS_HAS_OCR_SW) { 2814141cc406Sopenharmony_ci switch (dev->model->gpio_id) { 2815141cc406Sopenharmony_ci case GpioId::MD_5345: 2816141cc406Sopenharmony_ci session->buttons[BUTTON_OCR_SW].write(value == 0x13); 2817141cc406Sopenharmony_ci break; 2818141cc406Sopenharmony_ci default: 2819141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); 2820141cc406Sopenharmony_ci } 2821141cc406Sopenharmony_ci } 2822141cc406Sopenharmony_ci 2823141cc406Sopenharmony_ci // document detection 2824141cc406Sopenharmony_ci if (dev->model->buttons & GENESYS_HAS_PAGE_LOADED_SW) { 2825141cc406Sopenharmony_ci switch (dev->model->gpio_id) { 2826141cc406Sopenharmony_ci case GpioId::XP200: 2827141cc406Sopenharmony_ci session->buttons[BUTTON_PAGE_LOADED_SW].write((value & 0x04) != 0); 2828141cc406Sopenharmony_ci break; 2829141cc406Sopenharmony_ci default: 2830141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); 2831141cc406Sopenharmony_ci } 2832141cc406Sopenharmony_ci } 2833141cc406Sopenharmony_ci 2834141cc406Sopenharmony_ci /* XPA detection */ 2835141cc406Sopenharmony_ci if (dev->model->has_method(ScanMethod::TRANSPARENCY)) { 2836141cc406Sopenharmony_ci switch (dev->model->gpio_id) { 2837141cc406Sopenharmony_ci case GpioId::HP3670: 2838141cc406Sopenharmony_ci case GpioId::HP2400: 2839141cc406Sopenharmony_ci /* test if XPA is plugged-in */ 2840141cc406Sopenharmony_ci if ((value & 0x40) == 0) { 2841141cc406Sopenharmony_ci session->opt[OPT_SOURCE].cap &= ~SANE_CAP_INACTIVE; 2842141cc406Sopenharmony_ci } else { 2843141cc406Sopenharmony_ci session->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE; 2844141cc406Sopenharmony_ci } 2845141cc406Sopenharmony_ci break; 2846141cc406Sopenharmony_ci default: 2847141cc406Sopenharmony_ci throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); 2848141cc406Sopenharmony_ci } 2849141cc406Sopenharmony_ci } 2850141cc406Sopenharmony_ci} 2851141cc406Sopenharmony_ci 2852141cc406Sopenharmony_civoid CommandSetGl646::update_home_sensor_gpio(Genesys_Device& dev) const 2853141cc406Sopenharmony_ci{ 2854141cc406Sopenharmony_ci DBG_HELPER(dbg); 2855141cc406Sopenharmony_ci (void) dev; 2856141cc406Sopenharmony_ci} 2857141cc406Sopenharmony_ci 2858141cc406Sopenharmony_cistatic void write_control(Genesys_Device* dev, const Genesys_Sensor& sensor, int resolution) 2859141cc406Sopenharmony_ci{ 2860141cc406Sopenharmony_ci DBG_HELPER(dbg); 2861141cc406Sopenharmony_ci std::uint8_t control[4]; 2862141cc406Sopenharmony_ci std::uint32_t addr = 0xdead; 2863141cc406Sopenharmony_ci 2864141cc406Sopenharmony_ci /* 2300 does not write to 'control' */ 2865141cc406Sopenharmony_ci if (dev->model->motor_id == MotorId::HP2300) { 2866141cc406Sopenharmony_ci return; 2867141cc406Sopenharmony_ci } 2868141cc406Sopenharmony_ci 2869141cc406Sopenharmony_ci /* MD6471/G2410/HP2300 and XP200 read/write data from an undocumented memory area which 2870141cc406Sopenharmony_ci * is after the second slope table */ 2871141cc406Sopenharmony_ci switch (sensor.full_resolution) 2872141cc406Sopenharmony_ci { 2873141cc406Sopenharmony_ci case 600: 2874141cc406Sopenharmony_ci addr = 0x08200; 2875141cc406Sopenharmony_ci break; 2876141cc406Sopenharmony_ci case 1200: 2877141cc406Sopenharmony_ci addr = 0x10200; 2878141cc406Sopenharmony_ci break; 2879141cc406Sopenharmony_ci case 2400: 2880141cc406Sopenharmony_ci addr = 0x1fa00; 2881141cc406Sopenharmony_ci break; 2882141cc406Sopenharmony_ci default: 2883141cc406Sopenharmony_ci throw SaneException("failed to compute control address"); 2884141cc406Sopenharmony_ci } 2885141cc406Sopenharmony_ci 2886141cc406Sopenharmony_ci /* XP200 sets dpi, what other scanner put is unknown yet */ 2887141cc406Sopenharmony_ci switch (dev->model->motor_id) 2888141cc406Sopenharmony_ci { 2889141cc406Sopenharmony_ci case MotorId::XP200: 2890141cc406Sopenharmony_ci /* we put scan's dpi, not motor one */ 2891141cc406Sopenharmony_ci control[0] = resolution & 0xff; 2892141cc406Sopenharmony_ci control[1] = (resolution >> 8) & 0xff; 2893141cc406Sopenharmony_ci control[2] = dev->control[4]; 2894141cc406Sopenharmony_ci control[3] = dev->control[5]; 2895141cc406Sopenharmony_ci break; 2896141cc406Sopenharmony_ci case MotorId::HP3670: 2897141cc406Sopenharmony_ci case MotorId::HP2400: 2898141cc406Sopenharmony_ci case MotorId::MD_5345: 2899141cc406Sopenharmony_ci default: 2900141cc406Sopenharmony_ci control[0] = dev->control[2]; 2901141cc406Sopenharmony_ci control[1] = dev->control[3]; 2902141cc406Sopenharmony_ci control[2] = dev->control[4]; 2903141cc406Sopenharmony_ci control[3] = dev->control[5]; 2904141cc406Sopenharmony_ci break; 2905141cc406Sopenharmony_ci } 2906141cc406Sopenharmony_ci 2907141cc406Sopenharmony_ci dev->interface->write_buffer(0x3c, addr, control, 4); 2908141cc406Sopenharmony_ci} 2909141cc406Sopenharmony_ci 2910141cc406Sopenharmony_civoid CommandSetGl646::wait_for_motor_stop(Genesys_Device* dev) const 2911141cc406Sopenharmony_ci{ 2912141cc406Sopenharmony_ci (void) dev; 2913141cc406Sopenharmony_ci} 2914141cc406Sopenharmony_ci 2915141cc406Sopenharmony_civoid CommandSetGl646::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, 2916141cc406Sopenharmony_ci std::uint8_t* data, int size) const 2917141cc406Sopenharmony_ci{ 2918141cc406Sopenharmony_ci (void) dev; 2919141cc406Sopenharmony_ci (void) sensor; 2920141cc406Sopenharmony_ci (void) data; 2921141cc406Sopenharmony_ci (void) size; 2922141cc406Sopenharmony_ci throw SaneException("not implemented"); 2923141cc406Sopenharmony_ci} 2924141cc406Sopenharmony_ci 2925141cc406Sopenharmony_ciScanSession CommandSetGl646::calculate_scan_session(const Genesys_Device* dev, 2926141cc406Sopenharmony_ci const Genesys_Sensor& sensor, 2927141cc406Sopenharmony_ci const Genesys_Settings& settings) const 2928141cc406Sopenharmony_ci{ 2929141cc406Sopenharmony_ci // compute distance to move 2930141cc406Sopenharmony_ci float move = 0; 2931141cc406Sopenharmony_ci if (!dev->model->is_sheetfed) { 2932141cc406Sopenharmony_ci move = dev->model->y_offset; 2933141cc406Sopenharmony_ci // add tl_y to base movement 2934141cc406Sopenharmony_ci } 2935141cc406Sopenharmony_ci move += settings.tl_y; 2936141cc406Sopenharmony_ci 2937141cc406Sopenharmony_ci if (move < 0) { 2938141cc406Sopenharmony_ci DBG(DBG_error, "%s: overriding negative move value %f\n", __func__, move); 2939141cc406Sopenharmony_ci move = 0; 2940141cc406Sopenharmony_ci } 2941141cc406Sopenharmony_ci 2942141cc406Sopenharmony_ci move = static_cast<float>((move * dev->motor.base_ydpi) / MM_PER_INCH); 2943141cc406Sopenharmony_ci float start = settings.tl_x; 2944141cc406Sopenharmony_ci if (settings.scan_method == ScanMethod::FLATBED) { 2945141cc406Sopenharmony_ci start += dev->model->x_offset; 2946141cc406Sopenharmony_ci } else { 2947141cc406Sopenharmony_ci start += dev->model->x_offset_ta; 2948141cc406Sopenharmony_ci } 2949141cc406Sopenharmony_ci start = static_cast<float>((start * settings.xres) / MM_PER_INCH); 2950141cc406Sopenharmony_ci 2951141cc406Sopenharmony_ci ScanSession session; 2952141cc406Sopenharmony_ci session.params.xres = settings.xres; 2953141cc406Sopenharmony_ci session.params.yres = settings.yres; 2954141cc406Sopenharmony_ci session.params.startx = static_cast<unsigned>(start); 2955141cc406Sopenharmony_ci session.params.starty = static_cast<unsigned>(move); 2956141cc406Sopenharmony_ci session.params.pixels = settings.pixels; 2957141cc406Sopenharmony_ci session.params.requested_pixels = settings.requested_pixels; 2958141cc406Sopenharmony_ci session.params.lines = settings.lines; 2959141cc406Sopenharmony_ci session.params.depth = settings.depth; 2960141cc406Sopenharmony_ci session.params.channels = settings.get_channels(); 2961141cc406Sopenharmony_ci session.params.scan_method = dev->settings.scan_method; 2962141cc406Sopenharmony_ci session.params.scan_mode = settings.scan_mode; 2963141cc406Sopenharmony_ci session.params.color_filter = settings.color_filter; 2964141cc406Sopenharmony_ci session.params.contrast_adjustment = settings.contrast; 2965141cc406Sopenharmony_ci session.params.brightness_adjustment = settings.brightness; 2966141cc406Sopenharmony_ci session.params.flags = ScanFlag::AUTO_GO_HOME; 2967141cc406Sopenharmony_ci if (settings.scan_method == ScanMethod::TRANSPARENCY) { 2968141cc406Sopenharmony_ci session.params.flags |= ScanFlag::USE_XPA; 2969141cc406Sopenharmony_ci } 2970141cc406Sopenharmony_ci compute_session(dev, session, sensor); 2971141cc406Sopenharmony_ci 2972141cc406Sopenharmony_ci return session; 2973141cc406Sopenharmony_ci} 2974141cc406Sopenharmony_ci 2975141cc406Sopenharmony_civoid CommandSetGl646::asic_boot(Genesys_Device *dev, bool cold) const 2976141cc406Sopenharmony_ci{ 2977141cc406Sopenharmony_ci (void) dev; 2978141cc406Sopenharmony_ci (void) cold; 2979141cc406Sopenharmony_ci throw SaneException("not implemented"); 2980141cc406Sopenharmony_ci} 2981141cc406Sopenharmony_ci 2982141cc406Sopenharmony_ci} // namespace gl646 2983141cc406Sopenharmony_ci} // namespace genesys 2984