1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt> 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci This file is part of the SANE package. 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 8141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 9141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 10141cc406Sopenharmony_ci License, or (at your option) any later version. 11141cc406Sopenharmony_ci 12141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 13141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 14141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15141cc406Sopenharmony_ci General Public License for more details. 16141cc406Sopenharmony_ci 17141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 18141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 19141cc406Sopenharmony_ci*/ 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci#include "device.h" 24141cc406Sopenharmony_ci#include "command_set.h" 25141cc406Sopenharmony_ci#include "low.h" 26141cc406Sopenharmony_ci#include "utilities.h" 27141cc406Sopenharmony_ci 28141cc406Sopenharmony_cinamespace genesys { 29141cc406Sopenharmony_ci 30141cc406Sopenharmony_cistd::vector<unsigned> MethodResolutions::get_resolutions() const 31141cc406Sopenharmony_ci{ 32141cc406Sopenharmony_ci std::vector<unsigned> ret; 33141cc406Sopenharmony_ci std::copy(resolutions_x.begin(), resolutions_x.end(), std::back_inserter(ret)); 34141cc406Sopenharmony_ci std::copy(resolutions_y.begin(), resolutions_y.end(), std::back_inserter(ret)); 35141cc406Sopenharmony_ci // sort in decreasing order 36141cc406Sopenharmony_ci 37141cc406Sopenharmony_ci std::sort(ret.begin(), ret.end(), std::greater<unsigned>()); 38141cc406Sopenharmony_ci ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); 39141cc406Sopenharmony_ci return ret; 40141cc406Sopenharmony_ci} 41141cc406Sopenharmony_ci 42141cc406Sopenharmony_ciconst MethodResolutions* Genesys_Model::get_resolution_settings_ptr(ScanMethod method) const 43141cc406Sopenharmony_ci{ 44141cc406Sopenharmony_ci for (const auto& res_for_method : resolutions) { 45141cc406Sopenharmony_ci for (auto res_method : res_for_method.methods) { 46141cc406Sopenharmony_ci if (res_method == method) { 47141cc406Sopenharmony_ci return &res_for_method; 48141cc406Sopenharmony_ci } 49141cc406Sopenharmony_ci } 50141cc406Sopenharmony_ci } 51141cc406Sopenharmony_ci return nullptr; 52141cc406Sopenharmony_ci 53141cc406Sopenharmony_ci} 54141cc406Sopenharmony_ciconst MethodResolutions& Genesys_Model::get_resolution_settings(ScanMethod method) const 55141cc406Sopenharmony_ci{ 56141cc406Sopenharmony_ci const auto* ptr = get_resolution_settings_ptr(method); 57141cc406Sopenharmony_ci if (ptr) 58141cc406Sopenharmony_ci return *ptr; 59141cc406Sopenharmony_ci 60141cc406Sopenharmony_ci throw SaneException("Could not find resolution settings for method %d", 61141cc406Sopenharmony_ci static_cast<unsigned>(method)); 62141cc406Sopenharmony_ci} 63141cc406Sopenharmony_ci 64141cc406Sopenharmony_cistd::vector<unsigned> Genesys_Model::get_resolutions(ScanMethod method) const 65141cc406Sopenharmony_ci{ 66141cc406Sopenharmony_ci return get_resolution_settings(method).get_resolutions(); 67141cc406Sopenharmony_ci} 68141cc406Sopenharmony_ci 69141cc406Sopenharmony_cibool Genesys_Model::has_method(ScanMethod method) const 70141cc406Sopenharmony_ci{ 71141cc406Sopenharmony_ci return get_resolution_settings_ptr(method) != nullptr; 72141cc406Sopenharmony_ci} 73141cc406Sopenharmony_ci 74141cc406Sopenharmony_ci 75141cc406Sopenharmony_ciGenesys_Device::~Genesys_Device() 76141cc406Sopenharmony_ci{ 77141cc406Sopenharmony_ci clear(); 78141cc406Sopenharmony_ci} 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_civoid Genesys_Device::clear() 81141cc406Sopenharmony_ci{ 82141cc406Sopenharmony_ci calib_file.clear(); 83141cc406Sopenharmony_ci 84141cc406Sopenharmony_ci calibration_cache.clear(); 85141cc406Sopenharmony_ci 86141cc406Sopenharmony_ci white_average_data.clear(); 87141cc406Sopenharmony_ci dark_average_data.clear(); 88141cc406Sopenharmony_ci} 89141cc406Sopenharmony_ci 90141cc406Sopenharmony_ciImagePipelineNodeBufferedCallableSource& Genesys_Device::get_pipeline_source() 91141cc406Sopenharmony_ci{ 92141cc406Sopenharmony_ci return static_cast<ImagePipelineNodeBufferedCallableSource&>(pipeline.front()); 93141cc406Sopenharmony_ci} 94141cc406Sopenharmony_ci 95141cc406Sopenharmony_cibool Genesys_Device::is_head_pos_known(ScanHeadId scan_head) const 96141cc406Sopenharmony_ci{ 97141cc406Sopenharmony_ci switch (scan_head) { 98141cc406Sopenharmony_ci case ScanHeadId::PRIMARY: return is_head_pos_primary_known_; 99141cc406Sopenharmony_ci case ScanHeadId::SECONDARY: return is_head_pos_secondary_known_; 100141cc406Sopenharmony_ci case ScanHeadId::ALL: return is_head_pos_primary_known_ && is_head_pos_secondary_known_; 101141cc406Sopenharmony_ci default: 102141cc406Sopenharmony_ci throw SaneException("Unknown scan head ID"); 103141cc406Sopenharmony_ci } 104141cc406Sopenharmony_ci} 105141cc406Sopenharmony_ciunsigned Genesys_Device::head_pos(ScanHeadId scan_head) const 106141cc406Sopenharmony_ci{ 107141cc406Sopenharmony_ci switch (scan_head) { 108141cc406Sopenharmony_ci case ScanHeadId::PRIMARY: return head_pos_primary_; 109141cc406Sopenharmony_ci case ScanHeadId::SECONDARY: return head_pos_secondary_; 110141cc406Sopenharmony_ci default: 111141cc406Sopenharmony_ci throw SaneException("Unknown scan head ID"); 112141cc406Sopenharmony_ci } 113141cc406Sopenharmony_ci} 114141cc406Sopenharmony_ci 115141cc406Sopenharmony_civoid Genesys_Device::set_head_pos_unknown(ScanHeadId scan_head) 116141cc406Sopenharmony_ci{ 117141cc406Sopenharmony_ci if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) { 118141cc406Sopenharmony_ci is_head_pos_primary_known_ = false; 119141cc406Sopenharmony_ci } 120141cc406Sopenharmony_ci if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) { 121141cc406Sopenharmony_ci is_head_pos_secondary_known_ = false; 122141cc406Sopenharmony_ci } 123141cc406Sopenharmony_ci} 124141cc406Sopenharmony_ci 125141cc406Sopenharmony_civoid Genesys_Device::set_head_pos_zero(ScanHeadId scan_head) 126141cc406Sopenharmony_ci{ 127141cc406Sopenharmony_ci if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) { 128141cc406Sopenharmony_ci head_pos_primary_ = 0; 129141cc406Sopenharmony_ci is_head_pos_primary_known_ = true; 130141cc406Sopenharmony_ci } 131141cc406Sopenharmony_ci if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) { 132141cc406Sopenharmony_ci head_pos_secondary_ = 0; 133141cc406Sopenharmony_ci is_head_pos_secondary_known_ = true; 134141cc406Sopenharmony_ci } 135141cc406Sopenharmony_ci} 136141cc406Sopenharmony_ci 137141cc406Sopenharmony_civoid Genesys_Device::advance_head_pos_by_session(ScanHeadId scan_head) 138141cc406Sopenharmony_ci{ 139141cc406Sopenharmony_ci int motor_steps = session.params.starty + 140141cc406Sopenharmony_ci (session.params.lines * motor.base_ydpi) / session.params.yres; 141141cc406Sopenharmony_ci auto direction = has_flag(session.params.flags, ScanFlag::REVERSE) ? Direction::BACKWARD 142141cc406Sopenharmony_ci : Direction::FORWARD; 143141cc406Sopenharmony_ci advance_head_pos_by_steps(scan_head, direction, motor_steps); 144141cc406Sopenharmony_ci} 145141cc406Sopenharmony_ci 146141cc406Sopenharmony_cistatic void advance_pos(unsigned& pos, Direction direction, unsigned offset) 147141cc406Sopenharmony_ci{ 148141cc406Sopenharmony_ci if (direction == Direction::FORWARD) { 149141cc406Sopenharmony_ci pos += offset; 150141cc406Sopenharmony_ci } else { 151141cc406Sopenharmony_ci if (pos < offset) { 152141cc406Sopenharmony_ci throw SaneException("Trying to advance head behind the home sensor"); 153141cc406Sopenharmony_ci } 154141cc406Sopenharmony_ci pos -= offset; 155141cc406Sopenharmony_ci } 156141cc406Sopenharmony_ci} 157141cc406Sopenharmony_ci 158141cc406Sopenharmony_civoid Genesys_Device::advance_head_pos_by_steps(ScanHeadId scan_head, Direction direction, 159141cc406Sopenharmony_ci unsigned steps) 160141cc406Sopenharmony_ci{ 161141cc406Sopenharmony_ci if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) { 162141cc406Sopenharmony_ci if (!is_head_pos_primary_known_) { 163141cc406Sopenharmony_ci throw SaneException("Trying to advance head while scanhead position is not known"); 164141cc406Sopenharmony_ci } 165141cc406Sopenharmony_ci advance_pos(head_pos_primary_, direction, steps); 166141cc406Sopenharmony_ci } 167141cc406Sopenharmony_ci if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) { 168141cc406Sopenharmony_ci if (!is_head_pos_secondary_known_) { 169141cc406Sopenharmony_ci throw SaneException("Trying to advance head while scanhead position is not known"); 170141cc406Sopenharmony_ci } 171141cc406Sopenharmony_ci advance_pos(head_pos_secondary_, direction, steps); 172141cc406Sopenharmony_ci } 173141cc406Sopenharmony_ci} 174141cc406Sopenharmony_ci 175141cc406Sopenharmony_civoid print_scan_position(std::ostream& out, const Genesys_Device& dev, ScanHeadId scan_head) 176141cc406Sopenharmony_ci{ 177141cc406Sopenharmony_ci if (dev.is_head_pos_known(scan_head)) { 178141cc406Sopenharmony_ci out << dev.head_pos(scan_head); 179141cc406Sopenharmony_ci } else { 180141cc406Sopenharmony_ci out <<"(unknown)"; 181141cc406Sopenharmony_ci } 182141cc406Sopenharmony_ci} 183141cc406Sopenharmony_ci 184141cc406Sopenharmony_cistd::ostream& operator<<(std::ostream& out, const Genesys_Device& dev) 185141cc406Sopenharmony_ci{ 186141cc406Sopenharmony_ci StreamStateSaver state_saver{out}; 187141cc406Sopenharmony_ci 188141cc406Sopenharmony_ci out << "Genesys_Device{\n" 189141cc406Sopenharmony_ci << std::hex 190141cc406Sopenharmony_ci << " vendorId: 0x" << dev.vendorId << '\n' 191141cc406Sopenharmony_ci << " productId: 0x" << dev.productId << '\n' 192141cc406Sopenharmony_ci << std::dec 193141cc406Sopenharmony_ci << " usb_mode: " << dev.usb_mode << '\n' 194141cc406Sopenharmony_ci << " file_name: " << dev.file_name << '\n' 195141cc406Sopenharmony_ci << " calib_file: " << dev.calib_file << '\n' 196141cc406Sopenharmony_ci << " force_calibration: " << dev.force_calibration << '\n' 197141cc406Sopenharmony_ci << " ignore_offsets: " << dev.ignore_offsets << '\n' 198141cc406Sopenharmony_ci << " model: (not printed)\n" 199141cc406Sopenharmony_ci << " reg: " << format_indent_braced_list(4, dev.reg) << '\n' 200141cc406Sopenharmony_ci << " initial_regs: " << format_indent_braced_list(4, dev.initial_regs) << '\n' 201141cc406Sopenharmony_ci << " settings: " << format_indent_braced_list(4, dev.settings) << '\n' 202141cc406Sopenharmony_ci << " frontend: " << format_indent_braced_list(4, dev.frontend) << '\n' 203141cc406Sopenharmony_ci << " frontend_initial: " << format_indent_braced_list(4, dev.frontend_initial) << '\n'; 204141cc406Sopenharmony_ci if (!dev.memory_layout.regs.empty()) { 205141cc406Sopenharmony_ci out << " memory_layout.regs: " 206141cc406Sopenharmony_ci << format_indent_braced_list(4, dev.memory_layout.regs) << '\n'; 207141cc406Sopenharmony_ci } 208141cc406Sopenharmony_ci out << " gpo.regs: " << format_indent_braced_list(4, dev.gpo.regs) << '\n' 209141cc406Sopenharmony_ci << " motor: " << format_indent_braced_list(4, dev.motor) << '\n' 210141cc406Sopenharmony_ci << " control[0..6]: " << std::hex 211141cc406Sopenharmony_ci << static_cast<unsigned>(dev.control[0]) << ' ' 212141cc406Sopenharmony_ci << static_cast<unsigned>(dev.control[1]) << ' ' 213141cc406Sopenharmony_ci << static_cast<unsigned>(dev.control[2]) << ' ' 214141cc406Sopenharmony_ci << static_cast<unsigned>(dev.control[3]) << ' ' 215141cc406Sopenharmony_ci << static_cast<unsigned>(dev.control[4]) << ' ' 216141cc406Sopenharmony_ci << static_cast<unsigned>(dev.control[5]) << '\n' << std::dec 217141cc406Sopenharmony_ci << " average_size: " << dev.average_size << '\n' 218141cc406Sopenharmony_ci << " calib_session: " << format_indent_braced_list(4, dev.calib_session) << '\n' 219141cc406Sopenharmony_ci << " gamma_override_tables[0].size(): " << dev.gamma_override_tables[0].size() << '\n' 220141cc406Sopenharmony_ci << " gamma_override_tables[1].size(): " << dev.gamma_override_tables[1].size() << '\n' 221141cc406Sopenharmony_ci << " gamma_override_tables[2].size(): " << dev.gamma_override_tables[2].size() << '\n' 222141cc406Sopenharmony_ci << " white_average_data.size(): " << dev.white_average_data.size() << '\n' 223141cc406Sopenharmony_ci << " dark_average_data.size(): " << dev.dark_average_data.size() << '\n' 224141cc406Sopenharmony_ci << " already_initialized: " << dev.already_initialized << '\n' 225141cc406Sopenharmony_ci << " scanhead_position[PRIMARY]: "; 226141cc406Sopenharmony_ci print_scan_position(out, dev, ScanHeadId::PRIMARY); 227141cc406Sopenharmony_ci out << '\n' 228141cc406Sopenharmony_ci << " scanhead_position[SECONDARY]: "; 229141cc406Sopenharmony_ci print_scan_position(out, dev, ScanHeadId::SECONDARY); 230141cc406Sopenharmony_ci out << '\n' 231141cc406Sopenharmony_ci << " read_active: " << dev.read_active << '\n' 232141cc406Sopenharmony_ci << " parking: " << dev.parking << '\n' 233141cc406Sopenharmony_ci << " document: " << dev.document << '\n' 234141cc406Sopenharmony_ci << " total_bytes_read: " << dev.total_bytes_read << '\n' 235141cc406Sopenharmony_ci << " total_bytes_to_read: " << dev.total_bytes_to_read << '\n' 236141cc406Sopenharmony_ci << " session: " << format_indent_braced_list(4, dev.session) << '\n' 237141cc406Sopenharmony_ci << " calibration_cache: (not printed)\n" 238141cc406Sopenharmony_ci << " line_count: " << dev.line_count << '\n' 239141cc406Sopenharmony_ci << " segment_order: " 240141cc406Sopenharmony_ci << format_indent_braced_list(4, format_vector_unsigned(4, dev.segment_order)) << '\n' 241141cc406Sopenharmony_ci << '}'; 242141cc406Sopenharmony_ci return out; 243141cc406Sopenharmony_ci} 244141cc406Sopenharmony_ci 245141cc406Sopenharmony_civoid apply_reg_settings_to_device_write_only(Genesys_Device& dev, 246141cc406Sopenharmony_ci const GenesysRegisterSettingSet& regs) 247141cc406Sopenharmony_ci{ 248141cc406Sopenharmony_ci GenesysRegisterSettingSet backup; 249141cc406Sopenharmony_ci for (const auto& reg : regs) { 250141cc406Sopenharmony_ci dev.interface->write_register(reg.address, reg.value); 251141cc406Sopenharmony_ci } 252141cc406Sopenharmony_ci} 253141cc406Sopenharmony_ci 254141cc406Sopenharmony_civoid apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs) 255141cc406Sopenharmony_ci{ 256141cc406Sopenharmony_ci apply_reg_settings_to_device_with_backup(dev, regs); 257141cc406Sopenharmony_ci} 258141cc406Sopenharmony_ci 259141cc406Sopenharmony_ciGenesysRegisterSettingSet 260141cc406Sopenharmony_ci apply_reg_settings_to_device_with_backup(Genesys_Device& dev, 261141cc406Sopenharmony_ci const GenesysRegisterSettingSet& regs) 262141cc406Sopenharmony_ci{ 263141cc406Sopenharmony_ci GenesysRegisterSettingSet backup; 264141cc406Sopenharmony_ci for (const auto& reg : regs) { 265141cc406Sopenharmony_ci std::uint8_t old_val = dev.interface->read_register(reg.address); 266141cc406Sopenharmony_ci std::uint8_t new_val = (old_val & ~reg.mask) | (reg.value & reg.mask); 267141cc406Sopenharmony_ci dev.interface->write_register(reg.address, new_val); 268141cc406Sopenharmony_ci 269141cc406Sopenharmony_ci using SettingType = GenesysRegisterSettingSet::SettingType; 270141cc406Sopenharmony_ci backup.push_back(SettingType{reg.address, 271141cc406Sopenharmony_ci static_cast<std::uint8_t>(old_val & reg.mask), 272141cc406Sopenharmony_ci reg.mask}); 273141cc406Sopenharmony_ci } 274141cc406Sopenharmony_ci return backup; 275141cc406Sopenharmony_ci} 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci} // namespace genesys 278