/* sane - Scanner Access Now Easy. Copyright (C) 2019 Povilas Kanapickas This file is part of the SANE package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #define DEBUG_DECLARE_ONLY #include "device.h" #include "command_set.h" #include "low.h" #include "utilities.h" namespace genesys { std::vector MethodResolutions::get_resolutions() const { std::vector ret; std::copy(resolutions_x.begin(), resolutions_x.end(), std::back_inserter(ret)); std::copy(resolutions_y.begin(), resolutions_y.end(), std::back_inserter(ret)); // sort in decreasing order std::sort(ret.begin(), ret.end(), std::greater()); ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); return ret; } const MethodResolutions* Genesys_Model::get_resolution_settings_ptr(ScanMethod method) const { for (const auto& res_for_method : resolutions) { for (auto res_method : res_for_method.methods) { if (res_method == method) { return &res_for_method; } } } return nullptr; } const MethodResolutions& Genesys_Model::get_resolution_settings(ScanMethod method) const { const auto* ptr = get_resolution_settings_ptr(method); if (ptr) return *ptr; throw SaneException("Could not find resolution settings for method %d", static_cast(method)); } std::vector Genesys_Model::get_resolutions(ScanMethod method) const { return get_resolution_settings(method).get_resolutions(); } bool Genesys_Model::has_method(ScanMethod method) const { return get_resolution_settings_ptr(method) != nullptr; } Genesys_Device::~Genesys_Device() { clear(); } void Genesys_Device::clear() { calib_file.clear(); calibration_cache.clear(); white_average_data.clear(); dark_average_data.clear(); } ImagePipelineNodeBufferedCallableSource& Genesys_Device::get_pipeline_source() { return static_cast(pipeline.front()); } bool Genesys_Device::is_head_pos_known(ScanHeadId scan_head) const { switch (scan_head) { case ScanHeadId::PRIMARY: return is_head_pos_primary_known_; case ScanHeadId::SECONDARY: return is_head_pos_secondary_known_; case ScanHeadId::ALL: return is_head_pos_primary_known_ && is_head_pos_secondary_known_; default: throw SaneException("Unknown scan head ID"); } } unsigned Genesys_Device::head_pos(ScanHeadId scan_head) const { switch (scan_head) { case ScanHeadId::PRIMARY: return head_pos_primary_; case ScanHeadId::SECONDARY: return head_pos_secondary_; default: throw SaneException("Unknown scan head ID"); } } void Genesys_Device::set_head_pos_unknown(ScanHeadId scan_head) { if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) { is_head_pos_primary_known_ = false; } if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) { is_head_pos_secondary_known_ = false; } } void Genesys_Device::set_head_pos_zero(ScanHeadId scan_head) { if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) { head_pos_primary_ = 0; is_head_pos_primary_known_ = true; } if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) { head_pos_secondary_ = 0; is_head_pos_secondary_known_ = true; } } void Genesys_Device::advance_head_pos_by_session(ScanHeadId scan_head) { int motor_steps = session.params.starty + (session.params.lines * motor.base_ydpi) / session.params.yres; auto direction = has_flag(session.params.flags, ScanFlag::REVERSE) ? Direction::BACKWARD : Direction::FORWARD; advance_head_pos_by_steps(scan_head, direction, motor_steps); } static void advance_pos(unsigned& pos, Direction direction, unsigned offset) { if (direction == Direction::FORWARD) { pos += offset; } else { if (pos < offset) { throw SaneException("Trying to advance head behind the home sensor"); } pos -= offset; } } void Genesys_Device::advance_head_pos_by_steps(ScanHeadId scan_head, Direction direction, unsigned steps) { if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) { if (!is_head_pos_primary_known_) { throw SaneException("Trying to advance head while scanhead position is not known"); } advance_pos(head_pos_primary_, direction, steps); } if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) { if (!is_head_pos_secondary_known_) { throw SaneException("Trying to advance head while scanhead position is not known"); } advance_pos(head_pos_secondary_, direction, steps); } } void print_scan_position(std::ostream& out, const Genesys_Device& dev, ScanHeadId scan_head) { if (dev.is_head_pos_known(scan_head)) { out << dev.head_pos(scan_head); } else { out <<"(unknown)"; } } std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev) { StreamStateSaver state_saver{out}; out << "Genesys_Device{\n" << std::hex << " vendorId: 0x" << dev.vendorId << '\n' << " productId: 0x" << dev.productId << '\n' << std::dec << " usb_mode: " << dev.usb_mode << '\n' << " file_name: " << dev.file_name << '\n' << " calib_file: " << dev.calib_file << '\n' << " force_calibration: " << dev.force_calibration << '\n' << " ignore_offsets: " << dev.ignore_offsets << '\n' << " model: (not printed)\n" << " reg: " << format_indent_braced_list(4, dev.reg) << '\n' << " initial_regs: " << format_indent_braced_list(4, dev.initial_regs) << '\n' << " settings: " << format_indent_braced_list(4, dev.settings) << '\n' << " frontend: " << format_indent_braced_list(4, dev.frontend) << '\n' << " frontend_initial: " << format_indent_braced_list(4, dev.frontend_initial) << '\n'; if (!dev.memory_layout.regs.empty()) { out << " memory_layout.regs: " << format_indent_braced_list(4, dev.memory_layout.regs) << '\n'; } out << " gpo.regs: " << format_indent_braced_list(4, dev.gpo.regs) << '\n' << " motor: " << format_indent_braced_list(4, dev.motor) << '\n' << " control[0..6]: " << std::hex << static_cast(dev.control[0]) << ' ' << static_cast(dev.control[1]) << ' ' << static_cast(dev.control[2]) << ' ' << static_cast(dev.control[3]) << ' ' << static_cast(dev.control[4]) << ' ' << static_cast(dev.control[5]) << '\n' << std::dec << " average_size: " << dev.average_size << '\n' << " calib_session: " << format_indent_braced_list(4, dev.calib_session) << '\n' << " gamma_override_tables[0].size(): " << dev.gamma_override_tables[0].size() << '\n' << " gamma_override_tables[1].size(): " << dev.gamma_override_tables[1].size() << '\n' << " gamma_override_tables[2].size(): " << dev.gamma_override_tables[2].size() << '\n' << " white_average_data.size(): " << dev.white_average_data.size() << '\n' << " dark_average_data.size(): " << dev.dark_average_data.size() << '\n' << " already_initialized: " << dev.already_initialized << '\n' << " scanhead_position[PRIMARY]: "; print_scan_position(out, dev, ScanHeadId::PRIMARY); out << '\n' << " scanhead_position[SECONDARY]: "; print_scan_position(out, dev, ScanHeadId::SECONDARY); out << '\n' << " read_active: " << dev.read_active << '\n' << " parking: " << dev.parking << '\n' << " document: " << dev.document << '\n' << " total_bytes_read: " << dev.total_bytes_read << '\n' << " total_bytes_to_read: " << dev.total_bytes_to_read << '\n' << " session: " << format_indent_braced_list(4, dev.session) << '\n' << " calibration_cache: (not printed)\n" << " line_count: " << dev.line_count << '\n' << " segment_order: " << format_indent_braced_list(4, format_vector_unsigned(4, dev.segment_order)) << '\n' << '}'; return out; } void apply_reg_settings_to_device_write_only(Genesys_Device& dev, const GenesysRegisterSettingSet& regs) { GenesysRegisterSettingSet backup; for (const auto& reg : regs) { dev.interface->write_register(reg.address, reg.value); } } void apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs) { apply_reg_settings_to_device_with_backup(dev, regs); } GenesysRegisterSettingSet apply_reg_settings_to_device_with_backup(Genesys_Device& dev, const GenesysRegisterSettingSet& regs) { GenesysRegisterSettingSet backup; for (const auto& reg : regs) { std::uint8_t old_val = dev.interface->read_register(reg.address); std::uint8_t new_val = (old_val & ~reg.mask) | (reg.value & reg.mask); dev.interface->write_register(reg.address, new_val); using SettingType = GenesysRegisterSettingSet::SettingType; backup.push_back(SettingType{reg.address, static_cast(old_val & reg.mask), reg.mask}); } return backup; } } // namespace genesys